Merge "Deprecate onMetadataChanged."
diff --git a/Android.mk b/Android.mk
index 370fe14..cca87ca 100644
--- a/Android.mk
+++ b/Android.mk
@@ -238,6 +238,7 @@
core/java/android/net/INetworkScoreService.aidl \
core/java/android/net/INetworkStatsService.aidl \
core/java/android/net/INetworkStatsSession.aidl \
+ core/java/android/net/ITetheringStatsProvider.aidl \
core/java/android/net/nsd/INsdManager.aidl \
core/java/android/nfc/IAppCallback.aidl \
core/java/android/nfc/INfcAdapter.aidl \
diff --git a/api/current.txt b/api/current.txt
index 21e66d3..37cb728 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31900,6 +31900,7 @@
method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
method public java.util.UUID getUuidForPath(java.io.File) throws java.io.IOException;
+ method public boolean isAllocationSupported(java.io.FileDescriptor);
method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException;
method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
method public boolean isEncrypted(java.io.File);
@@ -38683,14 +38684,18 @@
public final class StructStat {
ctor public StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long);
+ ctor public StructStat(long, long, int, long, int, int, long, long, android.system.StructTimespec, android.system.StructTimespec, android.system.StructTimespec, long, long);
+ field public final android.system.StructTimespec st_atim;
field public final long st_atime;
field public final long st_blksize;
field public final long st_blocks;
+ field public final android.system.StructTimespec st_ctim;
field public final long st_ctime;
field public final long st_dev;
field public final int st_gid;
field public final long st_ino;
field public final int st_mode;
+ field public final android.system.StructTimespec st_mtim;
field public final long st_mtime;
field public final long st_nlink;
field public final long st_rdev;
@@ -38713,6 +38718,13 @@
field public final long f_namemax;
}
+ public final class StructTimespec implements java.lang.Comparable {
+ ctor public StructTimespec(long, long);
+ method public int compareTo(android.system.StructTimespec);
+ field public final long tv_nsec;
+ field public final long tv_sec;
+ }
+
public final class StructUtsname {
ctor public StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
field public final java.lang.String machine;
@@ -49068,7 +49080,7 @@
method public void setNetworkAvailable(boolean);
method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
method public void setRendererPriorityPolicy(int, boolean);
- method public static void setSafeBrowsingWhiteList(java.util.List<java.lang.String>);
+ method public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
method public deprecated void setVerticalScrollbarOverlay(boolean);
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
diff --git a/api/removed.txt b/api/removed.txt
index 3968fd3..ca34142 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -267,6 +267,14 @@
}
+package android.net.wifi {
+
+ public class WifiManager {
+ method public deprecated boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
+ }
+
+}
+
package android.os {
public class BatteryManager {
@@ -302,18 +310,8 @@
package android.os.storage {
public class StorageManager {
- method public deprecated void allocateBytes(java.io.File, long, int) throws java.io.IOException;
- method public deprecated long getAllocatableBytes(java.io.File, int) throws java.io.IOException;
- method public deprecated long getCacheQuotaBytes(java.io.File) throws java.io.IOException;
- method public deprecated long getCacheQuotaBytes() throws java.io.IOException;
- method public deprecated long getCacheSizeBytes(java.io.File) throws java.io.IOException;
- method public deprecated long getCacheSizeBytes() throws java.io.IOException;
- method public deprecated long getExternalCacheQuotaBytes() throws java.io.IOException;
- method public deprecated long getExternalCacheSizeBytes() throws java.io.IOException;
method public android.os.storage.StorageVolume getPrimaryVolume();
method public android.os.storage.StorageVolume[] getVolumeList();
- method public deprecated boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException;
- method public deprecated void setCacheBehaviorAtomic(java.io.File, boolean) throws java.io.IOException;
}
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 63b2477..6979527 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -146,6 +146,7 @@
field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
+ field public static final java.lang.String MANAGE_FALLBACK_SUBSCRIPTION_PLANS = "android.permission.MANAGE_FALLBACK_SUBSCRIPTION_PLANS";
field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB";
field public static final java.lang.String MANAGE_USERS = "android.permission.MANAGE_USERS";
@@ -190,6 +191,8 @@
field public static final java.lang.String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
field public static final java.lang.String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
+ field public static final java.lang.String READ_PRINT_SERVICES = "android.permission.READ_PRINT_SERVICES";
+ field public static final java.lang.String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS";
field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
@@ -29246,7 +29249,7 @@
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
- method public boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
+ method public deprecated boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
method public boolean setWifiEnabled(boolean);
method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler);
method public deprecated boolean startLocationRestrictedScan(android.os.WorkSource);
@@ -34842,6 +34845,7 @@
method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
method public java.util.UUID getUuidForPath(java.io.File) throws java.io.IOException;
+ method public boolean isAllocationSupported(java.io.FileDescriptor);
method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException;
method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
method public boolean isEncrypted(java.io.File);
@@ -38625,6 +38629,22 @@
field public static final java.lang.String TYPE = "type";
}
+ public final class TimeZoneRulesDataContract {
+ field public static final java.lang.String AUTHORITY = "com.android.timezone";
+ }
+
+ public static final class TimeZoneRulesDataContract.Operation {
+ field public static final java.lang.String COLUMN_DISTRO_MAJOR_VERSION = "distro_major_version";
+ field public static final java.lang.String COLUMN_DISTRO_MINOR_VERSION = "distro_minor_version";
+ field public static final java.lang.String COLUMN_REVISION = "revision";
+ field public static final java.lang.String COLUMN_RULES_VERSION = "rules_version";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String TYPE_INSTALL = "INSTALL";
+ field public static final java.lang.String TYPE_NO_OP = "NOOP";
+ field public static final java.lang.String TYPE_UNINSTALL = "UNINSTALL";
+ }
+
public class UserDictionary {
ctor public UserDictionary();
field public static final java.lang.String AUTHORITY = "user_dictionary";
@@ -41986,14 +42006,18 @@
public final class StructStat {
ctor public StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long);
+ ctor public StructStat(long, long, int, long, int, int, long, long, android.system.StructTimespec, android.system.StructTimespec, android.system.StructTimespec, long, long);
+ field public final android.system.StructTimespec st_atim;
field public final long st_atime;
field public final long st_blksize;
field public final long st_blocks;
+ field public final android.system.StructTimespec st_ctim;
field public final long st_ctime;
field public final long st_dev;
field public final int st_gid;
field public final long st_ino;
field public final int st_mode;
+ field public final android.system.StructTimespec st_mtim;
field public final long st_mtime;
field public final long st_nlink;
field public final long st_rdev;
@@ -42016,6 +42040,13 @@
field public final long f_namemax;
}
+ public final class StructTimespec implements java.lang.Comparable {
+ ctor public StructTimespec(long, long);
+ method public int compareTo(android.system.StructTimespec);
+ field public final long tv_nsec;
+ field public final long tv_sec;
+ }
+
public final class StructUtsname {
ctor public StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
field public final java.lang.String machine;
@@ -52798,7 +52829,7 @@
method public void setNetworkAvailable(boolean);
method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
method public void setRendererPriorityPolicy(int, boolean);
- method public static void setSafeBrowsingWhiteList(java.util.List<java.lang.String>);
+ method public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
method public deprecated void setVerticalScrollbarOverlay(boolean);
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
@@ -53000,7 +53031,7 @@
method public abstract java.lang.String getDefaultUserAgent(android.content.Context);
method public abstract void initSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
method public abstract android.net.Uri[] parseFileChooserResult(int, android.content.Intent);
- method public abstract void setSafeBrowsingWhiteList(java.util.List<java.lang.String>);
+ method public abstract void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
method public abstract void setWebContentsDebuggingEnabled(boolean);
method public abstract void shutdownSafeBrowsing();
}
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 48f62b1..dfadae4 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -295,18 +295,8 @@
package android.os.storage {
public class StorageManager {
- method public deprecated void allocateBytes(java.io.File, long, int) throws java.io.IOException;
- method public deprecated long getAllocatableBytes(java.io.File, int) throws java.io.IOException;
- method public deprecated long getCacheQuotaBytes(java.io.File) throws java.io.IOException;
- method public deprecated long getCacheQuotaBytes() throws java.io.IOException;
- method public deprecated long getCacheSizeBytes(java.io.File) throws java.io.IOException;
- method public deprecated long getCacheSizeBytes() throws java.io.IOException;
- method public deprecated long getExternalCacheQuotaBytes() throws java.io.IOException;
- method public deprecated long getExternalCacheSizeBytes() throws java.io.IOException;
method public android.os.storage.StorageVolume getPrimaryVolume();
method public android.os.storage.StorageVolume[] getVolumeList();
- method public deprecated boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException;
- method public deprecated void setCacheBehaviorAtomic(java.io.File, boolean) throws java.io.IOException;
}
}
diff --git a/api/test-current.txt b/api/test-current.txt
index c2a1231..b9f9be5d2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -32041,6 +32041,7 @@
method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
method public java.util.UUID getUuidForPath(java.io.File) throws java.io.IOException;
+ method public boolean isAllocationSupported(java.io.FileDescriptor);
method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException;
method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
method public boolean isEncrypted(java.io.File);
@@ -32732,9 +32733,7 @@
public final class PrintManager {
method public java.util.List<android.print.PrintJob> getPrintJobs();
- method public java.util.List<android.printservice.PrintServiceInfo> getPrintServices(int);
method public android.print.PrintJob print(java.lang.String, android.print.PrintDocumentAdapter, android.print.PrintAttributes);
- field public static final int ALL_SERVICES = 3; // 0x3
}
public final class PrinterCapabilitiesInfo implements android.os.Parcelable {
@@ -32864,13 +32863,6 @@
field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
}
- public final class PrintServiceInfo implements android.os.Parcelable {
- method public int describeContents();
- method public android.content.ComponentName getComponentName();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.printservice.PrintServiceInfo> CREATOR;
- }
-
public abstract class PrinterDiscoverySession {
ctor public PrinterDiscoverySession();
method public final void addPrinters(java.util.List<android.print.PrinterInfo>);
@@ -38902,14 +38894,18 @@
public final class StructStat {
ctor public StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long);
+ ctor public StructStat(long, long, int, long, int, int, long, long, android.system.StructTimespec, android.system.StructTimespec, android.system.StructTimespec, long, long);
+ field public final android.system.StructTimespec st_atim;
field public final long st_atime;
field public final long st_blksize;
field public final long st_blocks;
+ field public final android.system.StructTimespec st_ctim;
field public final long st_ctime;
field public final long st_dev;
field public final int st_gid;
field public final long st_ino;
field public final int st_mode;
+ field public final android.system.StructTimespec st_mtim;
field public final long st_mtime;
field public final long st_nlink;
field public final long st_rdev;
@@ -38932,6 +38928,13 @@
field public final long f_namemax;
}
+ public final class StructTimespec implements java.lang.Comparable {
+ ctor public StructTimespec(long, long);
+ method public int compareTo(android.system.StructTimespec);
+ field public final long tv_nsec;
+ field public final long tv_sec;
+ }
+
public final class StructUtsname {
ctor public StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
field public final java.lang.String machine;
@@ -46190,6 +46193,7 @@
method public void setFocusable(int);
method public void setFocusableInTouchMode(boolean);
method public void setFocusedByDefault(boolean);
+ method public final void setFocusedInCluster();
method public void setForeground(android.graphics.drawable.Drawable);
method public void setForegroundGravity(int);
method public void setForegroundTintList(android.content.res.ColorStateList);
@@ -49498,7 +49502,7 @@
method public void setNetworkAvailable(boolean);
method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
method public void setRendererPriorityPolicy(int, boolean);
- method public static void setSafeBrowsingWhiteList(java.util.List<java.lang.String>);
+ method public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
method public deprecated void setVerticalScrollbarOverlay(boolean);
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 3968fd3..ca34142 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -267,6 +267,14 @@
}
+package android.net.wifi {
+
+ public class WifiManager {
+ method public deprecated boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
+ }
+
+}
+
package android.os {
public class BatteryManager {
@@ -302,18 +310,8 @@
package android.os.storage {
public class StorageManager {
- method public deprecated void allocateBytes(java.io.File, long, int) throws java.io.IOException;
- method public deprecated long getAllocatableBytes(java.io.File, int) throws java.io.IOException;
- method public deprecated long getCacheQuotaBytes(java.io.File) throws java.io.IOException;
- method public deprecated long getCacheQuotaBytes() throws java.io.IOException;
- method public deprecated long getCacheSizeBytes(java.io.File) throws java.io.IOException;
- method public deprecated long getCacheSizeBytes() throws java.io.IOException;
- method public deprecated long getExternalCacheQuotaBytes() throws java.io.IOException;
- method public deprecated long getExternalCacheSizeBytes() throws java.io.IOException;
method public android.os.storage.StorageVolume getPrimaryVolume();
method public android.os.storage.StorageVolume[] getVolumeList();
- method public deprecated boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException;
- method public deprecated void setCacheBehaviorAtomic(java.io.File, boolean) throws java.io.IOException;
}
}
diff --git a/cmds/bootanimation/BootAnimationUtil.cpp b/cmds/bootanimation/BootAnimationUtil.cpp
index 377d6ce..7718daf 100644
--- a/cmds/bootanimation/BootAnimationUtil.cpp
+++ b/cmds/bootanimation/BootAnimationUtil.cpp
@@ -29,7 +29,7 @@
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.nobootanimation", value, "0");
if (atoi(value) > 0) {
- return false;
+ return true;
}
property_get("ro.boot.quiescent", value, "0");
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index daac588..8501982 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -157,8 +157,10 @@
// create the boot animation object
sp<BootAnimation> boot = new BootAnimation(new AudioAnimationCallbacks());
+ ALOGV("Boot animation set up. Joining pool.");
IPCThreadState::self()->joinThreadPool();
}
+ ALOGV("Boot animation exit");
return 0;
}
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index 87e512c..bf9bd79 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -547,7 +547,9 @@
* @param authTokenType the type of auth token to retrieve after adding the account, may be null
* @param requiredFeatures a String array of authenticator-specific features that the added
* account must support, may be null
- * @param options a Bundle of authenticator-specific options, may be null
+ * @param options a Bundle of authenticator-specific options. It always contains
+ * {@link AccountManager#KEY_CALLER_PID} and {@link AccountManager#KEY_CALLER_UID}
+ * fields which will let authenticator know the identity of the caller.
* @return a Bundle result or null if the result is to be returned via the response. The result
* will contain either:
* <ul>
@@ -603,21 +605,24 @@
* addition {@link AbstractAccountAuthenticator} implementations that declare themselves
* {@code android:customTokens=true} may also provide a non-negative {@link
* #KEY_CUSTOM_TOKEN_EXPIRY} long value containing the expiration timestamp of the expiration
- * time (in millis since the unix epoch).
+ * time (in millis since the unix epoch), tokens will be cached in memory based on
+ * application's packageName/signature for however long that was specified.
* <p>
* Implementers should assume that tokens will be cached on the basis of account and
* authTokenType. The system may ignore the contents of the supplied options Bundle when
* determining to re-use a cached token. Furthermore, implementers should assume a supplied
* expiration time will be treated as non-binding advice.
* <p>
- * Finally, note that for android:customTokens=false authenticators, tokens are cached
+ * Finally, note that for {@code android:customTokens=false} authenticators, tokens are cached
* indefinitely until some client calls {@link
* AccountManager#invalidateAuthToken(String,String)}.
*
* @param response to send the result back to the AccountManager, will never be null
* @param account the account whose credentials are to be retrieved, will never be null
* @param authTokenType the type of auth token to retrieve, will never be null
- * @param options a Bundle of authenticator-specific options, may be null
+ * @param options a Bundle of authenticator-specific options. It always contains
+ * {@link AccountManager#KEY_CALLER_PID} and {@link AccountManager#KEY_CALLER_UID}
+ * fields which will let authenticator know the identity of the caller.
* @return a Bundle result or null if the result is to be returned via the response.
* @throws NetworkErrorException if the authenticator could not honor the request due to a
* network error
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index a446296..a209d28 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -242,10 +242,13 @@
public static final String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
/**
- * Authenticators using 'customTokens' option will also get the UID of the
- * caller
+ * The UID of caller app.
*/
public static final String KEY_CALLER_UID = "callerUid";
+
+ /**
+ * The process id of caller app.
+ */
public static final String KEY_CALLER_PID = "callerPid";
/**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3d2e061..21270c5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -6423,9 +6423,9 @@
private <T> T instantiate(ClassLoader cl, String className, Context c,
Instantiator<T> instantiator)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- if (c.getApplicationContext() instanceof Application) {
- T a = instantiator.instantiate((Application) c.getApplicationContext(),
- cl, className);
+ Application app = getApp(c);
+ if (app != null) {
+ T a = instantiator.instantiate(app, cl, className);
if (a != null) return a;
}
return (T) cl.loadClass(className).newInstance();
@@ -6434,14 +6434,25 @@
private <T> T instantiate(ClassLoader cl, String className, Intent intent, Context c,
IntentInstantiator<T> instantiator)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- if (c.getApplicationContext() instanceof Application) {
- T a = instantiator.instantiate((Application) c.getApplicationContext(),
- cl, className, intent);
+ Application app = getApp(c);
+ if (app != null) {
+ T a = instantiator.instantiate(app, cl, className, intent);
if (a != null) return a;
}
return (T) cl.loadClass(className).newInstance();
}
+ private Application getApp(Context c) {
+ // We need this shortcut to avoid actually calling getApplicationContext() on an Application
+ // because the Application may not return itself for getApplicationContext() because the
+ // API doesn't enforce it.
+ if (c instanceof Application) return (Application) c;
+ if (c.getApplicationContext() instanceof Application) {
+ return (Application) c.getApplicationContext();
+ }
+ return null;
+ }
+
private interface Instantiator<T> {
T instantiate(Application app, ClassLoader cl, String className)
throws ClassNotFoundException, IllegalAccessException, InstantiationException;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9c9d655..c48be77 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -60,12 +60,10 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -621,7 +619,8 @@
@Override
public File getExternalFilesDir(String type) {
// Operates on primary external storage
- return getExternalFilesDirs(type)[0];
+ final File[] dirs = getExternalFilesDirs(type);
+ return (dirs != null && dirs.length > 0) ? dirs[0] : null;
}
@Override
@@ -638,7 +637,8 @@
@Override
public File getObbDir() {
// Operates on primary external storage
- return getObbDirs()[0];
+ final File[] dirs = getObbDirs();
+ return (dirs != null && dirs.length > 0) ? dirs[0] : null;
}
@Override
@@ -672,7 +672,8 @@
@Override
public File getExternalCacheDir() {
// Operates on primary external storage
- return getExternalCacheDirs()[0];
+ final File[] dirs = getExternalCacheDirs();
+ return (dirs != null && dirs.length > 0) ? dirs[0] : null;
}
@Override
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 5baaeb3..b444f17 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -18,9 +18,9 @@
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.annotation.SdkConstant.SdkConstantType;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -36,8 +36,8 @@
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.provider.Downloads;
-import android.provider.Settings;
import android.provider.MediaStore.Images;
+import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import android.util.Pair;
@@ -393,7 +393,6 @@
private int mFlags = 0;
private boolean mIsVisibleInDownloadsUi = true;
private boolean mScannable = false;
- private boolean mUseSystemCache = false;
/** if a file is designated as a MediaScanner scannable file, the following value is
* stored in the database column {@link Downloads.Impl#COLUMN_MEDIA_SCANNED}.
*/
@@ -474,24 +473,6 @@
}
/**
- * Set the local destination for the downloaded file to the system cache dir (/cache).
- * This is only available to System apps with the permission
- * {@link android.Manifest.permission#ACCESS_CACHE_FILESYSTEM}.
- * <p>
- * The downloaded file is not scanned by MediaScanner.
- * But it can be made scannable by calling {@link #allowScanningByMediaScanner()}.
- * <p>
- * Files downloaded to /cache may be deleted by the system at any time to reclaim space.
- *
- * @return this object
- * @hide
- */
- public Request setDestinationToSystemCache() {
- mUseSystemCache = true;
- return this;
- }
-
- /**
* Set the local destination for the downloaded file to a path within
* the application's external files directory (as returned by
* {@link Context#getExternalFilesDir(String)}.
@@ -772,13 +753,13 @@
values.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, packageName);
if (mDestinationUri != null) {
- values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_FILE_URI);
- values.put(Downloads.Impl.COLUMN_FILE_NAME_HINT, mDestinationUri.toString());
+ values.put(Downloads.Impl.COLUMN_DESTINATION,
+ Downloads.Impl.DESTINATION_FILE_URI);
+ values.put(Downloads.Impl.COLUMN_FILE_NAME_HINT,
+ mDestinationUri.toString());
} else {
values.put(Downloads.Impl.COLUMN_DESTINATION,
- (this.mUseSystemCache) ?
- Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION :
- Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE);
+ Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE);
}
// is the file supposed to be media-scannable?
values.put(Downloads.Impl.COLUMN_MEDIA_SCANNED, (mScannable) ? SCANNABLE_VALUE_YES :
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 143d147..d6e3691 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -15,11 +15,6 @@
*/
package android.app;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-
import android.annotation.SystemApi;
import android.app.NotificationManager.Importance;
import android.content.Intent;
@@ -31,6 +26,11 @@
import android.service.notification.NotificationListenerService;
import android.text.TextUtils;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.IOException;
import java.util.Arrays;
@@ -743,7 +743,7 @@
private static String longArrayToString(long[] values) {
StringBuffer sb = new StringBuffer();
- if (values != null) {
+ if (values != null && values.length > 0) {
for (int i = 0; i < values.length - 1; i++) {
sb.append(values[i]).append(DELIMITER);
}
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 5a356d9..d0d98c9 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -659,13 +659,13 @@
* managed provisioning.
*
* <p>When provisioning of a managed profile is complete, the managed profile is hidden until
- * the profile owner calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}.
+ * the profile owner calls {@link DevicePolicyManager#setProfileEnabled(ComponentName admin)}.
* Typically a profile owner will enable the profile when it has finished any additional setup
- * such as adding an account by using the {@link AccountManager} and calling apis to bring the
+ * such as adding an account by using the {@link AccountManager} and calling APIs to bring the
* profile into the desired state.
*
* <p> Note that provisioning completes without waiting for any server interactions, so the
- * profile owner needs to wait for data to be available if required (e.g. android device ids or
+ * profile owner needs to wait for data to be available if required (e.g. Android device IDs or
* other data that is set as a result of server interactions).
*
* <p>From version {@link android.os.Build.VERSION_CODES#O}, when managed provisioning has
diff --git a/core/java/android/app/timezone/Callback.java b/core/java/android/app/timezone/Callback.java
index b51e5ba..aea8038 100644
--- a/core/java/android/app/timezone/Callback.java
+++ b/core/java/android/app/timezone/Callback.java
@@ -27,7 +27,6 @@
*
* @hide
*/
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
public abstract class Callback {
@Retention(RetentionPolicy.SOURCE)
diff --git a/core/java/android/app/timezone/DistroFormatVersion.java b/core/java/android/app/timezone/DistroFormatVersion.java
index e879e8f..be732e4 100644
--- a/core/java/android/app/timezone/DistroFormatVersion.java
+++ b/core/java/android/app/timezone/DistroFormatVersion.java
@@ -35,7 +35,6 @@
*
* @hide
*/
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
public final class DistroFormatVersion implements Parcelable {
private final int mMajorVersion;
diff --git a/core/java/android/app/timezone/DistroRulesVersion.java b/core/java/android/app/timezone/DistroRulesVersion.java
index 1eb9f45..a680594 100644
--- a/core/java/android/app/timezone/DistroRulesVersion.java
+++ b/core/java/android/app/timezone/DistroRulesVersion.java
@@ -36,7 +36,6 @@
*
* @hide
*/
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
public final class DistroRulesVersion implements Parcelable {
private final String mRulesVersion;
diff --git a/core/java/android/app/timezone/RulesManager.java b/core/java/android/app/timezone/RulesManager.java
index 649d894..ad9b698 100644
--- a/core/java/android/app/timezone/RulesManager.java
+++ b/core/java/android/app/timezone/RulesManager.java
@@ -64,7 +64,6 @@
* {@link Context#TIME_ZONE_RULES_MANAGER_SERVICE}.
* @hide
*/
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
public final class RulesManager {
private static final String TAG = "timezone.RulesManager";
private static final boolean DEBUG = false;
diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java
index 7d6ad21..ec247eb 100644
--- a/core/java/android/app/timezone/RulesState.java
+++ b/core/java/android/app/timezone/RulesState.java
@@ -60,7 +60,6 @@
*
* @hide
*/
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
public final class RulesState implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
diff --git a/core/java/android/app/timezone/RulesUpdaterContract.java b/core/java/android/app/timezone/RulesUpdaterContract.java
index 07b2f33..9c62f46 100644
--- a/core/java/android/app/timezone/RulesUpdaterContract.java
+++ b/core/java/android/app/timezone/RulesUpdaterContract.java
@@ -27,7 +27,6 @@
*
* @hide
*/
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
public final class RulesUpdaterContract {
/**
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index ed41e79..aa9562f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -608,15 +608,15 @@
}
/**
- * Get {@link ApplicationInfo} for a profile
+ * Returns {@link ApplicationInfo} about an application installed for a specific user profile.
*
* @param packageName The package name of the application
* @param flags Additional option flags {@link PackageManager#getApplicationInfo}
* @param user The UserHandle of the profile.
*
- * @return An {@link ApplicationInfo} containing information about the package or
- * null if the package isn't installed for the given user, or the target user
- * is not enabled.
+ * @return {@link ApplicationInfo} containing information about the package. Returns
+ * {@code null} if the package isn't installed for the given profile, or the profile
+ * isn't enabled.
*/
public ApplicationInfo getApplicationInfo(@NonNull String packageName,
@ApplicationInfoFlags int flags, @NonNull UserHandle user)
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/PackageBackwardCompatibility.java
new file mode 100644
index 0000000..4de160b
--- /dev/null
+++ b/core/java/android/content/pm/PackageBackwardCompatibility.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageParser.Package;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Modifies {@link Package} in order to maintain backwards compatibility.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class PackageBackwardCompatibility {
+
+ private static final String ANDROID_TEST_MOCK = "android.test.mock";
+
+ private static final String ANDROID_TEST_RUNNER = "android.test.runner";
+
+ /**
+ * Modify the shared libraries in the supplied {@link Package} to maintain backwards
+ * compatibility.
+ *
+ * @param pkg the {@link Package} to modify.
+ */
+ @VisibleForTesting
+ public static void modifySharedLibraries(Package pkg) {
+ ArrayList<String> usesLibraries = pkg.usesLibraries;
+ ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
+
+ usesLibraries = orgApacheHttpLegacy(usesLibraries);
+ usesOptionalLibraries = orgApacheHttpLegacy(usesOptionalLibraries);
+
+ // android.test.runner has a dependency on android.test.mock so if android.test.runner
+ // is present but android.test.mock is not then add android.test.mock.
+ boolean androidTestMockPresent = ArrayUtils.contains(usesLibraries, ANDROID_TEST_MOCK)
+ || ArrayUtils.contains(usesOptionalLibraries, ANDROID_TEST_MOCK);
+ if (ArrayUtils.contains(usesLibraries, ANDROID_TEST_RUNNER) && !androidTestMockPresent) {
+ usesLibraries.add(ANDROID_TEST_MOCK);
+ }
+ if (ArrayUtils.contains(usesOptionalLibraries, ANDROID_TEST_RUNNER)
+ && !androidTestMockPresent) {
+ usesOptionalLibraries.add(ANDROID_TEST_MOCK);
+ }
+
+ pkg.usesLibraries = usesLibraries;
+ pkg.usesOptionalLibraries = usesOptionalLibraries;
+ }
+
+ private static ArrayList<String> orgApacheHttpLegacy(@Nullable ArrayList<String> libraries) {
+ // "org.apache.http.legacy" is now a part of the boot classpath so it doesn't need
+ // to be an explicit dependency.
+ //
+ // A future change will remove this library from the boot classpath, at which point
+ // all apps that target SDK 21 and earlier will have it automatically added to their
+ // dependency lists.
+ return ArrayUtils.remove(libraries, "org.apache.http.legacy");
+ }
+}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 426c4f2..a37e89e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3846,7 +3846,7 @@
// every activity info has had a chance to set it from its attributes.
setMaxAspectRatio(owner);
- modifySharedLibrariesForBackwardCompatibility(owner);
+ PackageBackwardCompatibility.modifySharedLibraries(owner);
if (hasDomainURLs(owner)) {
owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
@@ -3857,18 +3857,6 @@
return true;
}
- private static void modifySharedLibrariesForBackwardCompatibility(Package owner) {
- // "org.apache.http.legacy" is now a part of the boot classpath so it doesn't need
- // to be an explicit dependency.
- //
- // A future change will remove this library from the boot classpath, at which point
- // all apps that target SDK 21 and earlier will have it automatically added to their
- // dependency lists.
- owner.usesLibraries = ArrayUtils.remove(owner.usesLibraries, "org.apache.http.legacy");
- owner.usesOptionalLibraries = ArrayUtils.remove(owner.usesOptionalLibraries,
- "org.apache.http.legacy");
- }
-
/**
* Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
*/
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 23591c7..a8b8c4b 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -15,9 +15,6 @@
*/
package android.content.res;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.animation.Animator;
import android.animation.StateListAnimator;
import android.annotation.AnyRes;
@@ -32,7 +29,7 @@
import android.content.pm.ActivityInfo.Config;
import android.content.res.Configuration.NativeConfig;
import android.content.res.Resources.NotFoundException;
-import android.graphics.FontFamily;
+import android.graphics.Bitmap;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -40,8 +37,9 @@
import android.icu.text.PluralRules;
import android.os.Build;
import android.os.LocaleList;
+import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.Trace;
-import android.text.FontConfig;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -51,10 +49,12 @@
import android.util.Xml;
import android.view.DisplayAdjustments;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
-import java.util.List;
import java.util.Locale;
/**
@@ -72,9 +72,20 @@
private static final boolean DEBUG_LOAD = false;
private static final boolean DEBUG_CONFIG = false;
- private static final boolean TRACE_FOR_PRELOAD = false;
- private static final boolean TRACE_FOR_MISS_PRELOAD = false;
+ static final String TAG_PRELOAD = TAG + ".preload";
+
+ private static final boolean TRACE_FOR_PRELOAD = false; // Do we still need it?
+ private static final boolean TRACE_FOR_MISS_PRELOAD = false; // Do we still need it?
+
+ public static final boolean TRACE_FOR_DETAILED_PRELOAD =
+ SystemProperties.getBoolean("debug.trace_resource_preload", false);
+
+ /** Used only when TRACE_FOR_DETAILED_PRELOAD is true. */
+ private static int sPreloadTracingNumLoadedDrawables;
+ private long mPreloadTracingPreloadStartTime;
+ private long mPreloadTracingStartBitmapSize;
+ private long mPreloadTracingStartBitmapCount;
private static final int ID_OTHER = 0x01000004;
@@ -593,6 +604,16 @@
Drawable dr;
boolean needsNewDrawableAfterCache = false;
if (cs != null) {
+ if (TRACE_FOR_DETAILED_PRELOAD) {
+ // Log only framework resources
+ if (((id >>> 24) == 0x1) && (android.os.Process.myUid() != 0)) {
+ final String name = getResourceName(id);
+ if (name != null) {
+ Log.d(TAG_PRELOAD, "Hit preloaded FW drawable #"
+ + Integer.toHexString(id) + " " + name);
+ }
+ }
+ }
dr = cs.newDrawable(wrapper);
} else if (isColorDrawable) {
dr = new ColorDrawable(value.data);
@@ -744,6 +765,18 @@
}
}
+ // For prelaod tracing.
+ long startTime = 0;
+ int startBitmapCount = 0;
+ long startBitmapSize = 0;
+ int startDrwableCount = 0;
+ if (TRACE_FOR_DETAILED_PRELOAD) {
+ startTime = System.nanoTime();
+ startBitmapCount = Bitmap.sPreloadTracingNumInstantiatedBitmaps;
+ startBitmapSize = Bitmap.sPreloadTracingTotalBitmapsSize;
+ startDrwableCount = sPreloadTracingNumLoadedDrawables;
+ }
+
if (DEBUG_LOAD) {
Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
}
@@ -772,6 +805,37 @@
}
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ if (TRACE_FOR_DETAILED_PRELOAD) {
+ if (((id >>> 24) == 0x1)) {
+ final String name = getResourceName(id);
+ if (name != null) {
+ final long time = System.nanoTime() - startTime;
+ final int loadedBitmapCount =
+ Bitmap.sPreloadTracingNumInstantiatedBitmaps - startBitmapCount;
+ final long loadedBitmapSize =
+ Bitmap.sPreloadTracingTotalBitmapsSize - startBitmapSize;
+ final int loadedDrawables =
+ sPreloadTracingNumLoadedDrawables - startDrwableCount;
+
+ sPreloadTracingNumLoadedDrawables++;
+
+ final boolean isRoot = (android.os.Process.myUid() == 0);
+
+ Log.d(TAG_PRELOAD,
+ (isRoot ? "Preloaded FW drawable #"
+ : "Loaded non-preloaded FW drawable #")
+ + Integer.toHexString(id)
+ + " " + name
+ + " " + file
+ + " " + dr.getClass().getCanonicalName()
+ + " #nested_drawables= " + loadedDrawables
+ + " #bitmaps= " + loadedBitmapCount
+ + " total_bitmap_size= " + loadedBitmapSize
+ + " in[us] " + (time / 1000));
+ }
+ }
+ }
+
return dr;
}
@@ -1102,6 +1166,13 @@
mPreloading = true;
mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
updateConfiguration(null, null, null);
+
+ if (TRACE_FOR_DETAILED_PRELOAD) {
+ mPreloadTracingPreloadStartTime = SystemClock.uptimeMillis();
+ mPreloadTracingStartBitmapSize = Bitmap.sPreloadTracingTotalBitmapsSize;
+ mPreloadTracingStartBitmapCount = Bitmap.sPreloadTracingNumInstantiatedBitmaps;
+ Log.d(TAG_PRELOAD, "Preload starting");
+ }
}
}
@@ -1111,6 +1182,16 @@
*/
void finishPreloading() {
if (mPreloading) {
+ if (TRACE_FOR_DETAILED_PRELOAD) {
+ final long time = SystemClock.uptimeMillis() - mPreloadTracingPreloadStartTime;
+ final long size =
+ Bitmap.sPreloadTracingTotalBitmapsSize - mPreloadTracingStartBitmapSize;
+ final long count = Bitmap.sPreloadTracingNumInstantiatedBitmaps
+ - mPreloadTracingStartBitmapCount;
+ Log.d(TAG_PRELOAD, "Preload finished, "
+ + count + " bitmaps of " + size + " bytes in " + time + " ms");
+ }
+
mPreloading = false;
flushLayoutCache();
}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 4bc62b1..e1cd451 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -894,8 +894,9 @@
* to free up resource in sensor system associated with the direct channel.
*
* @param mem A {@link android.os.MemoryFile} shared memory object.
- * @return A {@link android.hardware.SensorDirectChannel} object if successful, null otherwise.
+ * @return A {@link android.hardware.SensorDirectChannel} object.
* @throws NullPointerException when mem is null.
+ * @throws UncheckedIOException if not able to create channel.
* @see SensorDirectChannel#close()
* @see #configureDirectChannel(SensorDirectChannel, Sensor, int)
*/
@@ -916,9 +917,9 @@
* to free up resource in sensor system associated with the direct channel.
*
* @param mem A {@link android.hardware.HardwareBuffer} shared memory object.
- * @return A {@link android.hardware.SensorDirectChannel} object if successful,
- * null otherwise.
+ * @return A {@link android.hardware.SensorDirectChannel} object.
* @throws NullPointerException when mem is null.
+ * @throws UncheckedIOException if not able to create channel.
* @see SensorDirectChannel#close()
* @see #configureDirectChannel(SensorDirectChannel, Sensor, int)
*/
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 1b150bf..90bf896 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -16,28 +16,29 @@
package android.hardware.camera2;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemService;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
import android.content.Context;
-import android.hardware.ICameraService;
-import android.hardware.ICameraServiceListener;
import android.hardware.CameraInfo;
import android.hardware.CameraStatus;
+import android.hardware.ICameraService;
+import android.hardware.ICameraServiceListener;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.legacy.CameraDeviceUserShim;
import android.hardware.camera2.legacy.LegacyMetadataMapper;
-import android.os.IBinder;
import android.os.Binder;
import android.os.DeadObjectException;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
-import android.util.Log;
+import android.os.SystemProperties;
import android.util.ArrayMap;
+import android.util.Log;
import java.util.ArrayList;
@@ -210,7 +211,9 @@
public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId)
throws CameraAccessException {
CameraCharacteristics characteristics = null;
-
+ if (CameraManagerGlobal.sCameraServiceDisabled) {
+ throw new IllegalArgumentException("No cameras available on device");
+ }
synchronized (mLock) {
/*
* Get the camera characteristics from the camera service directly if it supports it,
@@ -462,6 +465,9 @@
"Handler argument is null, but no looper exists in the calling thread");
}
}
+ if (CameraManagerGlobal.sCameraServiceDisabled) {
+ throw new IllegalArgumentException("No cameras available on device");
+ }
openCameraDeviceUserAsync(cameraId, callback, handler, clientUid);
}
@@ -507,6 +513,9 @@
*/
public void setTorchMode(@NonNull String cameraId, boolean enabled)
throws CameraAccessException {
+ if (CameraManagerGlobal.sCameraServiceDisabled) {
+ throw new IllegalArgumentException("No cameras available on device");
+ }
CameraManagerGlobal.get().setTorchMode(cameraId, enabled);
}
@@ -745,6 +754,9 @@
private CameraManagerGlobal() {
}
+ public static final boolean sCameraServiceDisabled =
+ SystemProperties.getBoolean("config.disable_cameraservice", false);
+
public static CameraManagerGlobal get() {
return gCameraManager;
}
@@ -764,7 +776,7 @@
public ICameraService getCameraService() {
synchronized(mLock) {
connectCameraServiceLocked();
- if (mCameraService == null) {
+ if (mCameraService == null && !sCameraServiceDisabled) {
Log.e(TAG, "Camera service is unavailable");
}
return mCameraService;
@@ -779,7 +791,7 @@
*/
private void connectCameraServiceLocked() {
// Only reconnect if necessary
- if (mCameraService != null) return;
+ if (mCameraService != null || sCameraServiceDisabled) return;
Log.i(TAG, "Connecting to camera service");
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
index d5d428e..0465def 100644
--- a/core/java/android/hardware/location/NanoApp.java
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -56,10 +56,10 @@
* {@link #setAppBinary(byte[])} and {@link #setAppId(long)} must be called
* prior to passing this object to any managers.
*
- * @see #NanoApp(int, byte[])
+ * @see #NanoApp(long, byte[])
*/
public NanoApp() {
- this(0, null);
+ this(0L, null);
mAppIdSet = false;
}
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 9b5d0d3..5b15c0d 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.Build;
@@ -257,6 +258,7 @@
* @hide
*/
@SystemApi
+ @SuppressLint("Doclava125")
public boolean resetDevice() {
return native_reset_device();
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2979cd8..7a1d85c 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1720,14 +1720,8 @@
// ignored
}
- /**
- * Return quota status for the current active network, or {@code null} if no
- * network is active. Quota status can change rapidly, so these values
- * shouldn't be cached.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ /** {@hide} */
+ @Deprecated
public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
try {
return mService.getActiveNetworkQuotaInfo();
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 63bbd96..7b948a7 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -21,6 +21,7 @@
import android.net.NetworkQuotaInfo;
import android.net.NetworkState;
import android.net.NetworkTemplate;
+import android.telephony.SubscriptionPlan;
/**
* Interface that creates and modifies network policy rules.
@@ -63,9 +64,14 @@
int getRestrictBackgroundByCaller();
void setDeviceIdleMode(boolean enabled);
+ void setWifiMeteredOverride(String networkId, int meteredOverride);
NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state);
- boolean isNetworkMetered(in NetworkState state);
+
+ SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage);
+ void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
+
+ String getSubscriptionPlanOwner(int subId);
void factoryReset(String subscriber);
}
diff --git a/core/java/android/net/ITetheringStatsProvider.aidl b/core/java/android/net/ITetheringStatsProvider.aidl
new file mode 100644
index 0000000..769086d
--- /dev/null
+++ b/core/java/android/net/ITetheringStatsProvider.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.NetworkStats;
+
+/**
+ * Interface that allows NetworkManagementService to query for tethering statistics.
+ *
+ * TODO: this does not really need to be an interface since Tethering runs in the same process
+ * as NetworkManagementService. Consider refactoring Tethering to use direct access to
+ * NetworkManagementService instead of using INetworkManagementService, and then deleting this
+ * interface.
+ *
+ * @hide
+ */
+interface ITetheringStatsProvider {
+ NetworkStats getTetherStats();
+}
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 84c32be..818aa21 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -16,8 +16,8 @@
package android.net;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
@@ -121,7 +121,6 @@
private boolean mIsFailover;
private boolean mIsAvailable;
private boolean mIsRoaming;
- private boolean mIsMetered;
/**
* @hide
@@ -154,7 +153,6 @@
mIsFailover = source.mIsFailover;
mIsAvailable = source.mIsAvailable;
mIsRoaming = source.mIsRoaming;
- mIsMetered = source.mIsMetered;
}
}
}
@@ -327,31 +325,6 @@
}
/**
- * Returns if this network is metered. A network is classified as metered
- * when the user is sensitive to heavy data usage on that connection due to
- * monetary costs, data limitations or battery/performance issues. You
- * should check this before doing large data transfers, and warn the user or
- * delay the operation until another network is available.
- *
- * @return {@code true} if large transfers should be avoided, otherwise
- * {@code false}.
- * @hide
- */
- public boolean isMetered() {
- synchronized (this) {
- return mIsMetered;
- }
- }
-
- /** {@hide} */
- @VisibleForTesting
- public void setMetered(boolean isMetered) {
- synchronized (this) {
- mIsMetered = isMetered;
- }
- }
-
- /**
* Reports the current coarse-grained state of the network.
* @return the coarse-grained state
*/
@@ -434,7 +407,6 @@
append(", failover: ").append(mIsFailover).
append(", available: ").append(mIsAvailable).
append(", roaming: ").append(mIsRoaming).
- append(", metered: ").append(mIsMetered).
append("]");
return builder.toString();
}
@@ -457,7 +429,6 @@
dest.writeInt(mIsFailover ? 1 : 0);
dest.writeInt(mIsAvailable ? 1 : 0);
dest.writeInt(mIsRoaming ? 1 : 0);
- dest.writeInt(mIsMetered ? 1 : 0);
dest.writeString(mReason);
dest.writeString(mExtraInfo);
}
@@ -476,7 +447,6 @@
netInfo.mIsFailover = in.readInt() != 0;
netInfo.mIsAvailable = in.readInt() != 0;
netInfo.mIsRoaming = in.readInt() != 0;
- netInfo.mIsMetered = in.readInt() != 0;
netInfo.mReason = in.readString();
netInfo.mExtraInfo = in.readString();
return netInfo;
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 9870e7b..edf9a28 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -46,17 +46,20 @@
public static final long SNOOZE_NEVER = -1;
public NetworkTemplate template;
- public int cycleDay;
- public String cycleTimezone;
- public long warningBytes;
- public long limitBytes;
- public long lastWarningSnooze;
- public long lastLimitSnooze;
- public boolean metered;
- public boolean inferred;
+ @Deprecated public int cycleDay = CYCLE_NONE;
+ @Deprecated public String cycleTimezone = "UTC";
+ public long warningBytes = WARNING_DISABLED;
+ public long limitBytes = LIMIT_DISABLED;
+ public long lastWarningSnooze = SNOOZE_NEVER;
+ public long lastLimitSnooze = SNOOZE_NEVER;
+ @Deprecated public boolean metered = true;
+ public boolean inferred = false;
private static final long DEFAULT_MTU = 1500;
+ public NetworkPolicy() {
+ }
+
@Deprecated
public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone,
long warningBytes, long limitBytes, boolean metered) {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 4d94a55..3fe9b0d 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -17,7 +17,6 @@
package android.net;
import static android.content.pm.PackageManager.GET_SIGNATURES;
-import static android.net.NetworkPolicy.CYCLE_NONE;
import android.annotation.SystemService;
import android.app.ActivityManager;
@@ -26,15 +25,19 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.telephony.SubscriptionPlan;
import android.util.DebugUtils;
+import android.util.Pair;
import com.google.android.collect.Sets;
-import java.util.Calendar;
+import java.time.ZonedDateTime;
import java.util.HashSet;
-import java.util.TimeZone;
+import java.util.Iterator;
/**
* Manager for creating and modifying network policy rules.
@@ -249,73 +252,9 @@
}
}
- /**
- * Compute the last cycle boundary for the given {@link NetworkPolicy}. For
- * example, if cycle day is 20th, and today is June 15th, it will return May
- * 20th. When cycle day doesn't exist in current month, it snaps to the 1st
- * of following month.
- *
- * @hide
- */
- public static long computeLastCycleBoundary(long currentTime, NetworkPolicy policy) {
- if (policy.cycleDay == CYCLE_NONE) {
- throw new IllegalArgumentException("Unable to compute boundary without cycleDay");
- }
-
- final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(policy.cycleTimezone));
- cal.setTimeInMillis(currentTime);
- snapToCycleDay(cal, policy.cycleDay);
-
- if (cal.getTimeInMillis() >= currentTime) {
- // Cycle boundary is beyond now, use last cycle boundary
- cal.set(Calendar.DAY_OF_MONTH, 1);
- cal.add(Calendar.MONTH, -1);
- snapToCycleDay(cal, policy.cycleDay);
- }
-
- return cal.getTimeInMillis();
- }
-
/** {@hide} */
- public static long computeNextCycleBoundary(long currentTime, NetworkPolicy policy) {
- if (policy.cycleDay == CYCLE_NONE) {
- throw new IllegalArgumentException("Unable to compute boundary without cycleDay");
- }
-
- final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(policy.cycleTimezone));
- cal.setTimeInMillis(currentTime);
- snapToCycleDay(cal, policy.cycleDay);
-
- if (cal.getTimeInMillis() <= currentTime) {
- // Cycle boundary is before now, use next cycle boundary
- cal.set(Calendar.DAY_OF_MONTH, 1);
- cal.add(Calendar.MONTH, 1);
- snapToCycleDay(cal, policy.cycleDay);
- }
-
- return cal.getTimeInMillis();
- }
-
- /**
- * Snap to the cycle day for the current month given; when cycle day doesn't
- * exist, it snaps to last second of current month.
- *
- * @hide
- */
- public static void snapToCycleDay(Calendar cal, int cycleDay) {
- cal.set(Calendar.HOUR_OF_DAY, 0);
- cal.set(Calendar.MINUTE, 0);
- cal.set(Calendar.SECOND, 0);
- if (cycleDay > cal.getActualMaximum(Calendar.DAY_OF_MONTH)) {
- cal.add(Calendar.MONTH, 1);
- cal.set(Calendar.DAY_OF_MONTH, 1);
- cal.set(Calendar.HOUR_OF_DAY, 0);
- cal.set(Calendar.MINUTE, 0);
- cal.set(Calendar.SECOND, 0);
- cal.add(Calendar.SECOND, -1);
- } else {
- cal.set(Calendar.DAY_OF_MONTH, cycleDay);
- }
+ public static Iterator<Pair<ZonedDateTime, ZonedDateTime>> cycleIterator(NetworkPolicy policy) {
+ return SubscriptionPlan.convert(policy).cycleIterator();
}
/**
@@ -400,4 +339,13 @@
public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState) {
return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
}
+
+ public static String resolveNetworkId(WifiConfiguration config) {
+ return WifiInfo.removeDoubleQuotes(config.isPasspoint()
+ ? config.providerFriendlyName : config.SSID);
+ }
+
+ public static String resolveNetworkId(String ssid) {
+ return WifiInfo.removeDoubleQuotes(ssid);
+ }
}
diff --git a/core/java/android/net/NetworkQuotaInfo.java b/core/java/android/net/NetworkQuotaInfo.java
index 1725ed7..b95f1d9 100644
--- a/core/java/android/net/NetworkQuotaInfo.java
+++ b/core/java/android/net/NetworkQuotaInfo.java
@@ -20,41 +20,32 @@
import android.os.Parcelable;
/**
- * Information about quota status on a specific network.
- *
+ * @deprecated nobody should be using this, but keep it around returning stub
+ * values to prevent app crashes.
* @hide
*/
+@Deprecated
public class NetworkQuotaInfo implements Parcelable {
- private final long mEstimatedBytes;
- private final long mSoftLimitBytes;
- private final long mHardLimitBytes;
-
public static final long NO_LIMIT = -1;
/** {@hide} */
- public NetworkQuotaInfo(long estimatedBytes, long softLimitBytes, long hardLimitBytes) {
- mEstimatedBytes = estimatedBytes;
- mSoftLimitBytes = softLimitBytes;
- mHardLimitBytes = hardLimitBytes;
+ public NetworkQuotaInfo() {
}
/** {@hide} */
public NetworkQuotaInfo(Parcel in) {
- mEstimatedBytes = in.readLong();
- mSoftLimitBytes = in.readLong();
- mHardLimitBytes = in.readLong();
}
public long getEstimatedBytes() {
- return mEstimatedBytes;
+ return 0;
}
public long getSoftLimitBytes() {
- return mSoftLimitBytes;
+ return NO_LIMIT;
}
public long getHardLimitBytes() {
- return mHardLimitBytes;
+ return NO_LIMIT;
}
@Override
@@ -64,9 +55,6 @@
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeLong(mEstimatedBytes);
- out.writeLong(mSoftLimitBytes);
- out.writeLong(mHardLimitBytes);
}
public static final Creator<NetworkQuotaInfo> CREATOR = new Creator<NetworkQuotaInfo>() {
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 2d9860c..4b79cbb 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -99,7 +99,7 @@
* shut down the tunnel gracefully.</li>
* </ol>
*
- * <p>Services extended this class need to be declared with appropriate
+ * <p>Services extending this class need to be declared with an appropriate
* permission and intent filter. Their access must be secured by
* {@link android.Manifest.permission#BIND_VPN_SERVICE} permission, and
* their intent filter must match {@link #SERVICE_INTERFACE} action. Here
@@ -112,6 +112,13 @@
* </intent-filter>
* </service></pre>
*
+ * <p> The Android system starts a VPN in the background by calling
+ * {@link android.content.Context#startService startService()}. In Android 8.0
+ * (API level 26) and higher, the system places VPN apps on the temporary
+ * whitelist for a short period so the app can start in the background. The VPN
+ * app must promote itself to the foreground after it's launched or the system
+ * will shut down the app.
+ *
* @see Builder
*/
public class VpnService extends Service {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a34668c..41f090a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -16,15 +16,6 @@
package android.os;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Formatter;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
import android.app.job.JobParameters;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -43,6 +34,15 @@
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* A class providing access to battery usage statistics, including information on
* wakelocks, processes, packages, and services. All times are represented in microseconds
@@ -168,6 +168,11 @@
public static final int BLUETOOTH_UNOPTIMIZED_SCAN_ON = 21;
/**
+ * A constant indicating a foreground service timer
+ */
+ public static final int FOREGROUND_SERVICE = 22;
+
+ /**
* Include all of the data in the stats, including previously saved data.
*/
public static final int STATS_SINCE_CHARGED = 0;
@@ -223,7 +228,11 @@
private static final String CPU_TIMES_AT_FREQ_DATA = "ctf";
private static final String SENSOR_DATA = "sr";
private static final String VIBRATOR_DATA = "vib";
- private static final String FOREGROUND_DATA = "fg";
+ private static final String FOREGROUND_ACTIVITY_DATA = "fg";
+ // fgs line is:
+ // BATTERY_STATS_CHECKIN_VERSION, uid, category, "fgs",
+ // foreground service time, count
+ private static final String FOREGROUND_SERVICE_DATA = "fgs";
private static final String STATE_TIME_DATA = "st";
// wl line is:
// BATTERY_STATS_CHECKIN_VERSION, uid, which, "wl", name,
@@ -582,6 +591,11 @@
public abstract Timer getFlashlightTurnedOnTimer();
public abstract Timer getCameraTurnedOnTimer();
public abstract Timer getForegroundActivityTimer();
+
+ /**
+ * Returns the timer keeping track of Foreground Service time
+ */
+ public abstract Timer getForegroundServiceTimer();
public abstract Timer getBluetoothScanTimer();
public abstract Timer getBluetoothScanBackgroundTimer();
public abstract Timer getBluetoothUnoptimizedScanTimer();
@@ -3616,7 +3630,10 @@
dumpTimer(pw, uid, category, VIBRATOR_DATA, u.getVibratorOnTimer(),
rawRealtime, which);
- dumpTimer(pw, uid, category, FOREGROUND_DATA, u.getForegroundActivityTimer(),
+ dumpTimer(pw, uid, category, FOREGROUND_ACTIVITY_DATA, u.getForegroundActivityTimer(),
+ rawRealtime, which);
+
+ dumpTimer(pw, uid, category, FOREGROUND_SERVICE_DATA, u.getForegroundServiceTimer(),
rawRealtime, which);
final Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE];
@@ -5093,6 +5110,8 @@
"Vibrator");
uidActivity |= printTimer(pw, sb, u.getForegroundActivityTimer(), rawRealtime, which,
prefix, "Foreground activities");
+ uidActivity |= printTimer(pw, sb, u.getForegroundServiceTimer(), rawRealtime, which,
+ prefix, "Foreground services");
long totalStateTime = 0;
for (int ips=0; ips<Uid.NUM_PROCESS_STATE; ips++) {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index de59742..b46c6b1 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -223,28 +223,69 @@
/** @hide */
public static final int OTHER_OTHER_MEMTRACK = 16;
+ // Needs to be declared here for the DVK_STAT ranges below.
+ /** @hide */
+ public static final int NUM_OTHER_STATS = 17;
+
+ // Dalvik subsections.
/** @hide */
public static final int OTHER_DALVIK_NORMAL = 17;
/** @hide */
public static final int OTHER_DALVIK_LARGE = 18;
/** @hide */
- public static final int OTHER_DALVIK_LINEARALLOC = 19;
+ public static final int OTHER_DALVIK_ZYGOTE = 19;
/** @hide */
- public static final int OTHER_DALVIK_ACCOUNTING = 20;
+ public static final int OTHER_DALVIK_NON_MOVING = 20;
+ // Section begins and ends for dumpsys, relative to the DALVIK categories.
/** @hide */
- public static final int OTHER_DALVIK_CODE_CACHE = 21;
+ public static final int OTHER_DVK_STAT_DALVIK_START =
+ OTHER_DALVIK_NORMAL - NUM_OTHER_STATS;
/** @hide */
- public static final int OTHER_DALVIK_ZYGOTE = 22;
+ public static final int OTHER_DVK_STAT_DALVIK_END =
+ OTHER_DALVIK_NON_MOVING - NUM_OTHER_STATS;
+
+ // Dalvik Other subsections.
/** @hide */
- public static final int OTHER_DALVIK_NON_MOVING = 23;
+ public static final int OTHER_DALVIK_OTHER_LINEARALLOC = 21;
/** @hide */
- public static final int OTHER_DALVIK_INDIRECT_REFERENCE_TABLE = 24;
+ public static final int OTHER_DALVIK_OTHER_ACCOUNTING = 22;
+ /** @hide */
+ public static final int OTHER_DALVIK_OTHER_CODE_CACHE = 23;
+ /** @hide */
+ public static final int OTHER_DALVIK_OTHER_COMPILER_METADATA = 24;
+ /** @hide */
+ public static final int OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE = 25;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_DALVIK_OTHER_START =
+ OTHER_DALVIK_OTHER_LINEARALLOC - NUM_OTHER_STATS;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_DALVIK_OTHER_END =
+ OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE - NUM_OTHER_STATS;
+
+ // Dex subsections (Boot vdex, App dex, and App vdex).
+ /** @hide */
+ public static final int OTHER_DEX_BOOT_VDEX = 26;
+ /** @hide */
+ public static final int OTHER_DEX_APP_DEX = 27;
+ /** @hide */
+ public static final int OTHER_DEX_APP_VDEX = 28;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_DEX_START = OTHER_DEX_BOOT_VDEX - NUM_OTHER_STATS;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_DEX_END = OTHER_DEX_APP_VDEX - NUM_OTHER_STATS;
+
+ // Art subsections (App image, boot image).
+ /** @hide */
+ public static final int OTHER_ART_APP = 29;
+ /** @hide */
+ public static final int OTHER_ART_BOOT = 30;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_ART_START = OTHER_ART_APP - NUM_OTHER_STATS;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_ART_END = OTHER_ART_BOOT - NUM_OTHER_STATS;
/** @hide */
- public static final int NUM_OTHER_STATS = 17;
-
- /** @hide */
- public static final int NUM_DVK_STATS = 8;
+ public static final int NUM_DVK_STATS = 14;
/** @hide */
public static final int NUM_CATEGORIES = 8;
@@ -408,12 +449,18 @@
case OTHER_OTHER_MEMTRACK: return "Other mtrack";
case OTHER_DALVIK_NORMAL: return ".Heap";
case OTHER_DALVIK_LARGE: return ".LOS";
- case OTHER_DALVIK_LINEARALLOC: return ".LinearAlloc";
- case OTHER_DALVIK_ACCOUNTING: return ".GC";
- case OTHER_DALVIK_CODE_CACHE: return ".JITCache";
case OTHER_DALVIK_ZYGOTE: return ".Zygote";
case OTHER_DALVIK_NON_MOVING: return ".NonMoving";
- case OTHER_DALVIK_INDIRECT_REFERENCE_TABLE: return ".IndirectRef";
+ case OTHER_DALVIK_OTHER_LINEARALLOC: return ".LinearAlloc";
+ case OTHER_DALVIK_OTHER_ACCOUNTING: return ".GC";
+ case OTHER_DALVIK_OTHER_CODE_CACHE: return ".JITCache";
+ case OTHER_DALVIK_OTHER_COMPILER_METADATA: return ".CompilerMetadata";
+ case OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE: return ".IndirectRef";
+ case OTHER_DEX_BOOT_VDEX: return ".Boot vdex";
+ case OTHER_DEX_APP_DEX: return ".App dex";
+ case OTHER_DEX_APP_VDEX: return ".App vdex";
+ case OTHER_ART_APP: return ".App art";
+ case OTHER_ART_BOOT: return ".Boot art";
default: return "????";
}
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 92e78bc..3de2174 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -20,6 +20,7 @@
import android.net.InterfaceConfiguration;
import android.net.INetd;
import android.net.INetworkManagementEventObserver;
+import android.net.ITetheringStatsProvider;
import android.net.Network;
import android.net.NetworkStats;
import android.net.RouteInfo;
@@ -207,6 +208,18 @@
void disableNat(String internalInterface, String externalInterface);
/**
+ * Registers a {@code ITetheringStatsProvider} to provide tethering statistics.
+ * All registered providers will be called in order, and their results will be added together.
+ * Netd is always registered as a tethering stats provider.
+ */
+ void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name);
+
+ /**
+ * Unregisters a previously-registered {@code ITetheringStatsProvider}.
+ */
+ void unregisterTetheringStatsProvider(ITetheringStatsProvider provider);
+
+ /**
** PPPD
**/
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 1f8de04..7fa1c5a 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -751,7 +751,9 @@
// Block until the ordered broadcast has completed.
condition.block();
- wipeEuiccData(context, wipeEuicc);
+ // TODO(b/63693573): Uncomment this once the pSIM slot is restored as needed
+ // after the ensuing boot. Currently you end up stuck on the eSIM.
+ // wipeEuiccData(context, wipeEuicc);
String shutdownArg = null;
if (shutdown) {
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 71f5ff7..6372113 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -739,7 +739,7 @@
* {@link Environment#getDataDirectory()}, the returned value will be
* {@link #UUID_DEFAULT}.
*
- * @throws IOException when the storage device at the given path isn't
+ * @throws IOException when the storage device hosting the given path isn't
* present, or when it doesn't have a valid UUID.
*/
public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
@@ -771,6 +771,19 @@
throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid);
}
+ /**
+ * Test if the given file descriptor supports allocation of disk space using
+ * {@link #allocateBytes(FileDescriptor, long)}.
+ */
+ public boolean isAllocationSupported(@NonNull FileDescriptor fd) {
+ try {
+ getUuidForPath(ParcelFileDescriptor.getFile(fd));
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
/** {@hide} */
public @NonNull List<VolumeInfo> getVolumes() {
try {
@@ -1562,12 +1575,6 @@
}
}
- /** @removed */
- @Deprecated
- public long getCacheQuotaBytes(@NonNull File path) throws IOException {
- return getCacheQuotaBytes(getUuidForPath(path));
- }
-
/**
* Return total size in bytes of all cached data belonging to the calling
* app on the given storage volume.
@@ -1603,36 +1610,6 @@
}
}
- /** @removed */
- @Deprecated
- public long getCacheSizeBytes(@NonNull File path) throws IOException {
- return getCacheSizeBytes(getUuidForPath(path));
- }
-
- /** @removed */
- @Deprecated
- public long getCacheQuotaBytes() throws IOException {
- return getCacheQuotaBytes(mContext.getCacheDir());
- }
-
- /** @removed */
- @Deprecated
- public long getCacheSizeBytes() throws IOException {
- return getCacheSizeBytes(mContext.getCacheDir());
- }
-
- /** @removed */
- @Deprecated
- public long getExternalCacheQuotaBytes() throws IOException {
- return getCacheQuotaBytes(mContext.getExternalCacheDir());
- }
-
- /** @removed */
- @Deprecated
- public long getExternalCacheSizeBytes() throws IOException {
- return getCacheSizeBytes(mContext.getExternalCacheDir());
- }
-
/**
* Flag indicating that a disk space allocation request should operate in an
* aggressive mode. This flag should only be rarely used in situations that
@@ -1741,15 +1718,6 @@
}
}
- /** @removed */
- @Deprecated
- @WorkerThread
- @SuppressLint("Doclava125")
- public long getAllocatableBytes(@NonNull File path,
- @RequiresPermission @AllocateFlags int flags) throws IOException {
- return getAllocatableBytes(getUuidForPath(path), flags);
- }
-
/**
* Allocate the requested number of bytes for your application to use on the
* given storage volume. This will cause the system to delete any cached
@@ -1798,15 +1766,6 @@
}
}
- /** @removed */
- @Deprecated
- @WorkerThread
- @SuppressLint("Doclava125")
- public void allocateBytes(@NonNull File path, @BytesLong long bytes,
- @RequiresPermission @AllocateFlags int flags) throws IOException {
- allocateBytes(getUuidForPath(path), bytes, flags);
- }
-
/**
* Allocate the requested number of bytes for your application to use in the
* given open file. This will cause the system to delete any cached files
@@ -1834,6 +1793,7 @@
* doesn't support allocating space, or if the device had
* trouble allocating the requested space.
* @see #getAllocatableBytes(UUID, int)
+ * @see #isAllocationSupported(FileDescriptor)
* @see Environment#isExternalStorageEmulated(File)
*/
@WorkerThread
@@ -1848,17 +1808,28 @@
public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
final File file = ParcelFileDescriptor.getFile(fd);
+ final UUID uuid = getUuidForPath(file);
for (int i = 0; i < 3; i++) {
try {
final long haveBytes = Os.fstat(fd).st_blocks * 512;
final long needBytes = bytes - haveBytes;
if (needBytes > 0) {
- allocateBytes(file, needBytes, flags);
+ allocateBytes(uuid, needBytes, flags);
}
- Os.posix_fallocate(fd, 0, bytes);
- return;
+ try {
+ Os.posix_fallocate(fd, 0, bytes);
+ return;
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) {
+ Log.w(TAG, "fallocate() not supported; falling back to ftruncate()");
+ Os.ftruncate(fd, bytes);
+ return;
+ } else {
+ throw e;
+ }
+ }
} catch (ErrnoException e) {
if (e.errno == OsConstants.ENOSPC) {
Log.w(TAG, "Odd, not enough space; let's try again?");
@@ -1941,18 +1912,6 @@
return isCacheBehavior(path, XATTR_CACHE_GROUP);
}
- /** @removed */
- @Deprecated
- public void setCacheBehaviorAtomic(File path, boolean atomic) throws IOException {
- setCacheBehaviorGroup(path, atomic);
- }
-
- /** @removed */
- @Deprecated
- public boolean isCacheBehaviorAtomic(File path) throws IOException {
- return isCacheBehaviorGroup(path);
- }
-
/**
* Enable or disable special cache behavior that leaves deleted cache files
* intact as tombstones.
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 52dccb4..51b7798 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -18,9 +18,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.annotation.TestApi;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.content.ComponentName;
@@ -142,7 +142,6 @@
* @see #getPrintServices
* @hide
*/
- @TestApi
public static final int ALL_SERVICES = ENABLED_SERVICES | DISABLED_SERVICES;
/**
@@ -554,6 +553,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICES)
public void addPrintServicesChangeListener(@NonNull PrintServicesChangeListener listener,
@Nullable Handler handler) {
Preconditions.checkNotNull(listener);
@@ -589,6 +589,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICES)
public void removePrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
Preconditions.checkNotNull(listener);
@@ -629,8 +630,8 @@
*
* @hide
*/
- @TestApi
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICES)
public @NonNull List<PrintServiceInfo> getPrintServices(int selectionFlags) {
Preconditions.checkFlagsArgument(selectionFlags, ALL_SERVICES);
@@ -656,6 +657,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS)
public void addPrintServiceRecommendationsChangeListener(
@NonNull PrintServiceRecommendationsChangeListener listener,
@Nullable Handler handler) {
@@ -692,6 +694,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS)
public void removePrintServiceRecommendationsChangeListener(
@NonNull PrintServiceRecommendationsChangeListener listener) {
Preconditions.checkNotNull(listener);
@@ -731,6 +734,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS)
public @NonNull List<RecommendationInfo> getPrintServiceRecommendations() {
try {
List<RecommendationInfo> recommendations =
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 5ef9319..57f1229 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -49,7 +48,6 @@
*
* @hide
*/
-@TestApi
@SystemApi
public final class PrintServiceInfo implements Parcelable {
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 9d83bd7..a2c5a92 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -485,6 +485,7 @@
* partition. This option is only used by system apps and so it requires
* android.permission.ACCESS_CACHE_FILESYSTEM permission.
*/
+ @Deprecated
public static final int DESTINATION_SYSTEMCACHE_PARTITION = 5;
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ffa38d4..cda7f59 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7744,6 +7744,16 @@
*/
public static final String CDMA_SUBSCRIPTION_MODE = "subscription_mode";
+ /**
+ * The default value for whether background data is enabled or not.
+ *
+ * Used by {@code NetworkPolicyManagerService}.
+ *
+ * @hide
+ */
+ public static final String DEFAULT_RESTRICT_BACKGROUND_DATA =
+ "default_restrict_background_data";
+
/** Inactivity timeout to track mobile data activity.
*
* If set to a positive integer, it indicates the inactivity timeout value in seconds to
diff --git a/core/java/android/provider/TimeZoneRulesDataContract.java b/core/java/android/provider/TimeZoneRulesDataContract.java
index a607563..33d2588 100644
--- a/core/java/android/provider/TimeZoneRulesDataContract.java
+++ b/core/java/android/provider/TimeZoneRulesDataContract.java
@@ -16,6 +16,7 @@
package android.provider;
+import android.annotation.SystemApi;
import android.net.Uri;
/**
@@ -24,7 +25,7 @@
*
* @hide
*/
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
+@SystemApi
public final class TimeZoneRulesDataContract {
private TimeZoneRulesDataContract() {}
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index bfc8636c..42282ac 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -48,7 +48,7 @@
byte[] sign(String name, in byte[] data);
int verify(String name, in byte[] data, in byte[] signature);
byte[] get_pubkey(String name);
- int grant(String name, int granteeUid);
+ String grant(String name, int granteeUid);
int ungrant(String name, int granteeUid);
long getmtime(String name, int uid);
int duplicate(String srcKey, int srcUid, String destKey, int destUid);
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 137cf57..ce678fc 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -17,7 +17,7 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.app.NotificationChannel;
+import android.app.Notification;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -48,6 +48,12 @@
* {@link NotificationAssistantService#onNotificationSnoozedUntilContext}.
*/
public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
+ /**
+ * Data type: String. Used to change what {@link Notification#getGroup() group} a notification
+ * belongs to.
+ * @hide
+ */
+ public static final String KEY_GROUP_KEY = "key_group_key";
/**
* Create a notification adjustment.
@@ -146,4 +152,11 @@
dest.writeBundle(mSignals);
dest.writeInt(mUser);
}
+
+ @Override
+ public String toString() {
+ return "Adjustment{"
+ + "mSignals=" + mSignals
+ + '}';
+ }
}
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 1aaf73e..2dbff10 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -72,8 +72,8 @@
private final SpanSet<ReplacementSpan> mReplacementSpanSpanSet =
new SpanSet<ReplacementSpan>(ReplacementSpan.class);
- private final UnderlineInfo mUnderlineInfo = new UnderlineInfo();
- private final ArrayList<UnderlineInfo> mUnderlines = new ArrayList();
+ private final DecorationInfo mDecorationInfo = new DecorationInfo();
+ private final ArrayList<DecorationInfo> mDecorations = new ArrayList();
private static final TextLine[] sCached = new TextLine[3];
@@ -704,9 +704,9 @@
fmi.leading = Math.max(fmi.leading, previousLeading);
}
- private static void drawUnderline(TextPaint wp, Canvas c, int color, float thickness,
- float xleft, float xright, float baseline) {
- final float underlineTop = baseline + wp.baselineShift + wp.getUnderlinePosition();
+ private static void drawStroke(TextPaint wp, Canvas c, int color, float position,
+ float thickness, float xleft, float xright, float baseline) {
+ final float strokeTop = baseline + wp.baselineShift + position;
final int previousColor = wp.getColor();
final Paint.Style previousStyle = wp.getStyle();
@@ -716,7 +716,7 @@
wp.setAntiAlias(true);
wp.setColor(color);
- c.drawRect(xleft, underlineTop, xright, underlineTop + thickness, wp);
+ c.drawRect(xleft, strokeTop, xright, strokeTop + thickness, wp);
wp.setStyle(previousStyle);
wp.setColor(previousColor);
@@ -750,7 +750,7 @@
* @param fmi receives metrics information, can be null
* @param needWidth true if the width of the run is needed
* @param offset the offset for the purpose of measuring
- * @param underlines the list of locations and paremeters for drawing underlines
+ * @param decorations the list of locations and paremeters for drawing decorations
* @return the signed width of the run based on the run direction; only
* valid if needWidth is true
*/
@@ -758,7 +758,7 @@
int contextStart, int contextEnd, boolean runIsRtl,
Canvas c, float x, int top, int y, int bottom,
FontMetricsInt fmi, boolean needWidth, int offset,
- @Nullable ArrayList<UnderlineInfo> underlines) {
+ @Nullable ArrayList<DecorationInfo> decorations) {
wp.setWordSpacing(mAddedWidth);
// Get metrics first (even for empty strings or "0" width runs)
@@ -773,8 +773,8 @@
float totalWidth = 0;
- final int numUnderlines = underlines == null ? 0 : underlines.size();
- if (needWidth || (c != null && (wp.bgColor != 0 || numUnderlines != 0 || runIsRtl))) {
+ final int numDecorations = decorations == null ? 0 : decorations.size();
+ if (needWidth || (c != null && (wp.bgColor != 0 || numDecorations != 0 || runIsRtl))) {
totalWidth = getRunAdvance(wp, start, end, contextStart, contextEnd, runIsRtl, offset);
}
@@ -800,37 +800,44 @@
wp.setColor(previousColor);
}
- if (numUnderlines != 0) {
- for (int i = 0; i < numUnderlines; i++) {
- final UnderlineInfo info = underlines.get(i);
+ if (numDecorations != 0) {
+ for (int i = 0; i < numDecorations; i++) {
+ final DecorationInfo info = decorations.get(i);
- final int underlineStart = Math.max(info.start, start);
- final int underlineEnd = Math.min(info.end, offset);
- float underlineStartAdvance = getRunAdvance(
- wp, start, end, contextStart, contextEnd, runIsRtl, underlineStart);
- float underlineEndAdvance = getRunAdvance(
- wp, start, end, contextStart, contextEnd, runIsRtl, underlineEnd);
- final float underlineXLeft, underlineXRight;
+ final int decorationStart = Math.max(info.start, start);
+ final int decorationEnd = Math.min(info.end, offset);
+ float decorationStartAdvance = getRunAdvance(
+ wp, start, end, contextStart, contextEnd, runIsRtl, decorationStart);
+ float decorationEndAdvance = getRunAdvance(
+ wp, start, end, contextStart, contextEnd, runIsRtl, decorationEnd);
+ final float decorationXLeft, decorationXRight;
if (runIsRtl) {
- underlineXLeft = rightX - underlineEndAdvance;
- underlineXRight = rightX - underlineStartAdvance;
+ decorationXLeft = rightX - decorationEndAdvance;
+ decorationXRight = rightX - decorationStartAdvance;
} else {
- underlineXLeft = leftX + underlineStartAdvance;
- underlineXRight = leftX + underlineEndAdvance;
+ decorationXLeft = leftX + decorationStartAdvance;
+ decorationXRight = leftX + decorationEndAdvance;
}
// Theoretically, there could be cases where both Paint's and TextPaint's
// setUnderLineText() are called. For backward compatibility, we need to draw
// both underlines, the one with custom color first.
if (info.underlineColor != 0) {
- drawUnderline(wp, c, info.underlineColor, info.underlineThickness,
- underlineXLeft, underlineXRight, y);
+ drawStroke(wp, c, info.underlineColor, wp.getUnderlinePosition(),
+ info.underlineThickness, decorationXLeft, decorationXRight, y);
}
if (info.isUnderlineText) {
final float thickness =
Math.max(((Paint) wp).getUnderlineThickness(), 1.0f);
- drawUnderline(wp, c, wp.getColor(), thickness,
- underlineXLeft, underlineXRight, y);
+ drawStroke(wp, c, wp.getColor(), wp.getUnderlinePosition(), thickness,
+ decorationXLeft, decorationXRight, y);
+ }
+
+ if (info.isStrikeThruText) {
+ final float thickness =
+ Math.max(((Paint) wp).getStrikeThruThickness(), 1.0f);
+ drawStroke(wp, c, wp.getColor(), wp.getStrikeThruPosition(), thickness,
+ decorationXLeft, decorationXRight, y);
}
}
}
@@ -919,20 +926,22 @@
return result;
}
- private static final class UnderlineInfo {
+ private static final class DecorationInfo {
+ public boolean isStrikeThruText;
public boolean isUnderlineText;
public int underlineColor;
public float underlineThickness;
public int start = -1;
public int end = -1;
- public boolean hasUnderline() {
- return isUnderlineText || underlineColor != 0;
+ public boolean hasDecoration() {
+ return isStrikeThruText || isUnderlineText || underlineColor != 0;
}
// Copies the info, but not the start and end range.
- public UnderlineInfo copyInfo() {
- final UnderlineInfo copy = new UnderlineInfo();
+ public DecorationInfo copyInfo() {
+ final DecorationInfo copy = new DecorationInfo();
+ copy.isStrikeThruText = isStrikeThruText;
copy.isUnderlineText = isUnderlineText;
copy.underlineColor = underlineColor;
copy.underlineThickness = underlineThickness;
@@ -940,7 +949,11 @@
}
}
- private void extractUnderlineInfo(@NonNull TextPaint paint, @NonNull UnderlineInfo info) {
+ private void extractDecorationInfo(@NonNull TextPaint paint, @NonNull DecorationInfo info) {
+ info.isStrikeThruText = paint.isStrikeThruText();
+ if (info.isStrikeThruText) {
+ paint.setStrikeThruText(false);
+ }
info.isUnderlineText = paint.isUnderlineText();
if (info.isUnderlineText) {
paint.setUnderlineText(false);
@@ -1047,8 +1060,8 @@
activePaint.set(mPaint);
int activeStart = i;
int activeEnd = mlimit;
- final UnderlineInfo underlineInfo = mUnderlineInfo;
- mUnderlines.clear();
+ final DecorationInfo decorationInfo = mDecorationInfo;
+ mDecorations.clear();
for (int j = i, jnext; j < mlimit; j = jnext) {
jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + inext) -
mStart;
@@ -1064,7 +1077,7 @@
span.updateDrawState(wp);
}
- extractUnderlineInfo(wp, underlineInfo);
+ extractDecorationInfo(wp, decorationInfo);
if (j == i) {
// First chunk of text. We can't handle it yet, since we may need to merge it
@@ -1079,24 +1092,24 @@
activeStart, activeEnd, mPaint.getHyphenEdit()));
x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x,
top, y, bottom, fmi, needWidth || activeEnd < measureLimit,
- Math.min(activeEnd, mlimit), mUnderlines);
+ Math.min(activeEnd, mlimit), mDecorations);
activeStart = j;
activePaint.set(wp);
- mUnderlines.clear();
+ mDecorations.clear();
} else {
// The present TextPaint is substantially equal to the last TextPaint except
- // perhaps for underlines. We just need to expand the active piece of text to
+ // perhaps for decorations. We just need to expand the active piece of text to
// include the present chunk, which we always do anyway. We don't need to save
// wp to activePaint, since they are already equal.
}
activeEnd = jnext;
- if (underlineInfo.hasUnderline()) {
- final UnderlineInfo copy = underlineInfo.copyInfo();
+ if (decorationInfo.hasDecoration()) {
+ final DecorationInfo copy = decorationInfo.copyInfo();
copy.start = j;
copy.end = jnext;
- mUnderlines.add(copy);
+ mDecorations.add(copy);
}
}
// Handle the final piece of text.
@@ -1104,7 +1117,7 @@
activeStart, activeEnd, mPaint.getHyphenEdit()));
x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, x,
top, y, bottom, fmi, needWidth || activeEnd < measureLimit,
- Math.min(activeEnd, mlimit), mUnderlines);
+ Math.min(activeEnd, mlimit), mDecorations);
}
return x - originalX;
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index e5bc32bb..fc56455 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -20,7 +20,11 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
+import android.icu.text.DecimalFormat;
import android.icu.text.MeasureFormat;
+import android.icu.text.NumberFormat;
+import android.icu.text.UnicodeSet;
+import android.icu.text.UnicodeSetSpanner;
import android.icu.util.Measure;
import android.icu.util.MeasureUnit;
import android.net.NetworkUtils;
@@ -28,6 +32,7 @@
import android.text.TextUtils;
import android.view.View;
+import java.math.BigDecimal;
import java.util.Locale;
/**
@@ -37,6 +42,8 @@
public final class Formatter {
/** {@hide} */
+ public static final int FLAG_DEFAULT = 0;
+ /** {@hide} */
public static final int FLAG_SHORTER = 1 << 0;
/** {@hide} */
public static final int FLAG_CALCULATE_ROUNDED = 1 << 1;
@@ -58,7 +65,9 @@
return context.getResources().getConfiguration().getLocales().get(0);
}
- /* Wraps the source string in bidi formatting characters in RTL locales */
+ /**
+ * Wraps the source string in bidi formatting characters in RTL locales.
+ */
private static String bidiWrap(@NonNull Context context, String source) {
final Locale locale = localeFromContext(context);
if (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL) {
@@ -87,12 +96,7 @@
* @return formatted string with the number
*/
public static String formatFileSize(@Nullable Context context, long sizeBytes) {
- if (context == null) {
- return "";
- }
- final BytesResult res = formatBytes(context.getResources(), sizeBytes, 0);
- return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
- res.value, res.units));
+ return formatFileSize(context, sizeBytes, FLAG_DEFAULT);
}
/**
@@ -100,88 +104,191 @@
* (showing fewer digits of precision).
*/
public static String formatShortFileSize(@Nullable Context context, long sizeBytes) {
+ return formatFileSize(context, sizeBytes, FLAG_SHORTER);
+ }
+
+ private static String formatFileSize(@Nullable Context context, long sizeBytes, int flags) {
if (context == null) {
return "";
}
- final BytesResult res = formatBytes(context.getResources(), sizeBytes, FLAG_SHORTER);
- return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
- res.value, res.units));
+ final RoundedBytesResult res = RoundedBytesResult.roundBytes(sizeBytes, flags);
+ return bidiWrap(context, formatRoundedBytesResult(context, res));
+ }
+
+ private static String getSuffixOverride(@NonNull Resources res, MeasureUnit unit) {
+ if (unit == MeasureUnit.BYTE) {
+ return res.getString(com.android.internal.R.string.byteShort);
+ } else { // unit == PETABYTE
+ return res.getString(com.android.internal.R.string.petabyteShort);
+ }
+ }
+
+ private static NumberFormat getNumberFormatter(Locale locale, int fractionDigits) {
+ final NumberFormat numberFormatter = NumberFormat.getInstance(locale);
+ numberFormatter.setMinimumFractionDigits(fractionDigits);
+ numberFormatter.setMaximumFractionDigits(fractionDigits);
+ numberFormatter.setGroupingUsed(false);
+ if (numberFormatter instanceof DecimalFormat) {
+ // We do this only for DecimalFormat, since in the general NumberFormat case, calling
+ // setRoundingMode may throw an exception.
+ numberFormatter.setRoundingMode(BigDecimal.ROUND_HALF_UP);
+ }
+ return numberFormatter;
+ }
+
+ private static String deleteFirstFromString(String source, String toDelete) {
+ final int location = source.indexOf(toDelete);
+ if (location == -1) {
+ return source;
+ } else {
+ return source.substring(0, location)
+ + source.substring(location + toDelete.length(), source.length());
+ }
+ }
+
+ private static String formatMeasureShort(Locale locale, NumberFormat numberFormatter,
+ float value, MeasureUnit units) {
+ final MeasureFormat measureFormatter = MeasureFormat.getInstance(
+ locale, MeasureFormat.FormatWidth.SHORT, numberFormatter);
+ return measureFormatter.format(new Measure(value, units));
+ }
+
+ private static final UnicodeSetSpanner SPACES_AND_CONTROLS =
+ new UnicodeSetSpanner(new UnicodeSet("[[:Zs:][:Cf:]]").freeze());
+
+ private static String formatRoundedBytesResult(
+ @NonNull Context context, @NonNull RoundedBytesResult input) {
+ final Locale locale = localeFromContext(context);
+ final NumberFormat numberFormatter = getNumberFormatter(locale, input.fractionDigits);
+ if (input.units == MeasureUnit.BYTE || input.units == PETABYTE) {
+ // ICU spells out "byte" instead of "B", and can't format petabytes yet.
+ final String formattedNumber = numberFormatter.format(input.value);
+ return context.getString(com.android.internal.R.string.fileSizeSuffix,
+ formattedNumber, getSuffixOverride(context.getResources(), input.units));
+ } else {
+ return formatMeasureShort(locale, numberFormatter, input.value, input.units);
+ }
}
/** {@hide} */
public static BytesResult formatBytes(Resources res, long sizeBytes, int flags) {
- final boolean isNegative = (sizeBytes < 0);
- float result = isNegative ? -sizeBytes : sizeBytes;
- int suffix = com.android.internal.R.string.byteShort;
- long mult = 1;
- if (result > 900) {
- suffix = com.android.internal.R.string.kilobyteShort;
- mult = 1000;
- result = result / 1000;
+ final RoundedBytesResult rounded = RoundedBytesResult.roundBytes(sizeBytes, flags);
+ final Locale locale = res.getConfiguration().getLocales().get(0);
+ final NumberFormat numberFormatter = getNumberFormatter(locale, rounded.fractionDigits);
+ final String formattedNumber = numberFormatter.format(rounded.value);
+ final String units;
+ if (rounded.units == MeasureUnit.BYTE || rounded.units == PETABYTE) {
+ // ICU spells out "byte" instead of "B", and can't format petabytes yet.
+ units = getSuffixOverride(res, rounded.units);
+ } else {
+ // Since ICU does not give us access to the pattern, we need to extract the unit string
+ // from ICU, which we do by taking out the formatted number out of the formatted string
+ // and trimming the result of spaces and controls.
+ final String formattedMeasure = formatMeasureShort(
+ locale, numberFormatter, rounded.value, rounded.units);
+ final String numberRemoved = deleteFirstFromString(formattedMeasure, formattedNumber);
+ units = SPACES_AND_CONTROLS.trim(numberRemoved).toString();
}
- if (result > 900) {
- suffix = com.android.internal.R.string.megabyteShort;
- mult *= 1000;
- result = result / 1000;
+ return new BytesResult(formattedNumber, units, rounded.roundedBytes);
+ }
+
+ /**
+ * ICU doesn't support PETABYTE yet. Fake it so that we can treat all units the same way.
+ * {@hide}
+ */
+ public static final MeasureUnit PETABYTE = MeasureUnit.internalGetInstance(
+ "digital", "petabyte");
+
+ /** {@hide} */
+ public static class RoundedBytesResult {
+ public final float value;
+ public final MeasureUnit units;
+ public final int fractionDigits;
+ public final long roundedBytes;
+
+ private RoundedBytesResult(
+ float value, MeasureUnit units, int fractionDigits, long roundedBytes) {
+ this.value = value;
+ this.units = units;
+ this.fractionDigits = fractionDigits;
+ this.roundedBytes = roundedBytes;
}
- if (result > 900) {
- suffix = com.android.internal.R.string.gigabyteShort;
- mult *= 1000;
- result = result / 1000;
- }
- if (result > 900) {
- suffix = com.android.internal.R.string.terabyteShort;
- mult *= 1000;
- result = result / 1000;
- }
- if (result > 900) {
- suffix = com.android.internal.R.string.petabyteShort;
- mult *= 1000;
- result = result / 1000;
- }
- // Note we calculate the rounded long by ourselves, but still let String.format()
- // compute the rounded value. String.format("%f", 0.1) might not return "0.1" due to
- // floating point errors.
- final int roundFactor;
- final String roundFormat;
- if (mult == 1 || result >= 100) {
- roundFactor = 1;
- roundFormat = "%.0f";
- } else if (result < 1) {
- roundFactor = 100;
- roundFormat = "%.2f";
- } else if (result < 10) {
- if ((flags & FLAG_SHORTER) != 0) {
- roundFactor = 10;
- roundFormat = "%.1f";
- } else {
- roundFactor = 100;
- roundFormat = "%.2f";
+
+ /**
+ * Returns a RoundedBytesResult object based on the input size in bytes and the rounding
+ * flags. The result can be used for formatting.
+ */
+ public static RoundedBytesResult roundBytes(long sizeBytes, int flags) {
+ final boolean isNegative = (sizeBytes < 0);
+ float result = isNegative ? -sizeBytes : sizeBytes;
+ MeasureUnit units = MeasureUnit.BYTE;
+ long mult = 1;
+ if (result > 900) {
+ units = MeasureUnit.KILOBYTE;
+ mult = 1000;
+ result = result / 1000;
}
- } else { // 10 <= result < 100
- if ((flags & FLAG_SHORTER) != 0) {
+ if (result > 900) {
+ units = MeasureUnit.MEGABYTE;
+ mult *= 1000;
+ result = result / 1000;
+ }
+ if (result > 900) {
+ units = MeasureUnit.GIGABYTE;
+ mult *= 1000;
+ result = result / 1000;
+ }
+ if (result > 900) {
+ units = MeasureUnit.TERABYTE;
+ mult *= 1000;
+ result = result / 1000;
+ }
+ if (result > 900) {
+ units = PETABYTE;
+ mult *= 1000;
+ result = result / 1000;
+ }
+ // Note we calculate the rounded long by ourselves, but still let NumberFormat compute
+ // the rounded value. NumberFormat.format(0.1) might not return "0.1" due to floating
+ // point errors.
+ final int roundFactor;
+ final int roundDigits;
+ if (mult == 1 || result >= 100) {
roundFactor = 1;
- roundFormat = "%.0f";
- } else {
+ roundDigits = 0;
+ } else if (result < 1) {
roundFactor = 100;
- roundFormat = "%.2f";
+ roundDigits = 2;
+ } else if (result < 10) {
+ if ((flags & FLAG_SHORTER) != 0) {
+ roundFactor = 10;
+ roundDigits = 1;
+ } else {
+ roundFactor = 100;
+ roundDigits = 2;
+ }
+ } else { // 10 <= result < 100
+ if ((flags & FLAG_SHORTER) != 0) {
+ roundFactor = 1;
+ roundDigits = 0;
+ } else {
+ roundFactor = 100;
+ roundDigits = 2;
+ }
}
+
+ if (isNegative) {
+ result = -result;
+ }
+
+ // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like
+ // 80PB so it's okay (for now)...
+ final long roundedBytes =
+ (flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
+ : (((long) Math.round(result * roundFactor)) * mult / roundFactor);
+
+ return new RoundedBytesResult(result, units, roundDigits, roundedBytes);
}
-
- if (isNegative) {
- result = -result;
- }
- final String roundedString = String.format(roundFormat, result);
-
- // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so
- // it's okay (for now)...
- final long roundedBytes =
- (flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
- : (((long) Math.round(result * roundFactor)) * mult / roundFactor);
-
- final String units = res.getString(suffix);
-
- return new BytesResult(roundedString, units, roundedBytes);
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5225121..6af01f66 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10180,6 +10180,7 @@
*
* @hide
*/
+ @TestApi
public final void setFocusedInCluster() {
setFocusedInCluster(findKeyboardNavigationCluster());
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 4def0d0..574137b 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -35,7 +35,7 @@
* Defines the width of the horizontal scrollbar and the height of the vertical scrollbar in
* dips
*/
- private static final int SCROLL_BAR_SIZE = 10;
+ private static final int SCROLL_BAR_SIZE = 4;
/**
* Duration of the fade when scrollbars fade away in milliseconds
@@ -354,7 +354,8 @@
mEdgeSlop = (int) (sizeAndDensity * EDGE_SLOP + 0.5f);
mFadingEdgeLength = (int) (sizeAndDensity * FADING_EDGE_LENGTH + 0.5f);
- mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
+ mScrollbarSize = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.config_scrollbarSize);
mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e38a55f..05f9da5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -28,7 +28,6 @@
import android.Manifest;
import android.animation.LayoutTransition;
import android.annotation.NonNull;
-import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ResourcesManager;
@@ -214,11 +213,8 @@
/**
* Always assign focus if a focusable View is available.
- *
- * @hide
*/
- @TestApi
- public static boolean sAlwaysAssignFocus;
+ private static boolean sAlwaysAssignFocus;
/**
* This list must only be modified by the main thread, so a lock is only needed when changing
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index ed2547f..4c38266 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1645,9 +1645,13 @@
* TODO: Add documentation for the format of the urls.
*
* @param urls the list of URLs
+ * @param callback will be called with true if URLs are successfully added to the whitelist. It
+ * will be called with false if any URLs are malformed. The callback will be run on the UI
+ * thread.
*/
- public static void setSafeBrowsingWhiteList(@Nullable List<String> urls) {
- getFactory().getStatics().setSafeBrowsingWhiteList(urls);
+ public static void setSafeBrowsingWhitelist(@Nullable List<String> urls,
+ @Nullable ValueCallback<Boolean> callback) {
+ getFactory().getStatics().setSafeBrowsingWhitelist(urls, callback);
}
/**
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index da064d4..e7e539c 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.IntDef;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Message;
@@ -23,6 +24,9 @@
import android.view.KeyEvent;
import android.view.ViewRootImpl;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
public class WebViewClient {
/**
@@ -237,6 +241,16 @@
/** Resource load was cancelled by Safe Browsing */
public static final int ERROR_UNSAFE_RESOURCE = -16;
+ /** @hide */
+ @IntDef({
+ SAFE_BROWSING_THREAT_UNKNOWN,
+ SAFE_BROWSING_THREAT_MALWARE,
+ SAFE_BROWSING_THREAT_PHISHING,
+ SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SafeBrowsingThreat {}
+
/** The resource was blocked for an unknown reason */
public static final int SAFE_BROWSING_THREAT_UNKNOWN = 0;
/** The resource was blocked because it contains malware */
@@ -521,8 +535,8 @@
* SAFE_BROWSING_THREAT_* value.
* @param callback Applications must invoke one of the callback methods.
*/
- public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType,
- SafeBrowsingResponse callback) {
+ public void onSafeBrowsingHit(WebView view, WebResourceRequest request,
+ @SafeBrowsingThreat int threatType, SafeBrowsingResponse callback) {
callback.showInterstitial(/* allowReporting */ true);
}
}
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 9b31a0c..613eb72 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -91,9 +91,10 @@
/**
* Implement the API method
- * {@link android.webkit.WebView#setSafeBrowsingWhiteList(List<String>)}
+ * {@link android.webkit.WebView#setSafeBrowsingWhitelist(List<String>,
+ * ValueCallback<Boolean>)}
*/
- void setSafeBrowsingWhiteList(List<String> urls);
+ void setSafeBrowsingWhitelist(List<String> urls, ValueCallback<Boolean> callback);
}
Statics getStatics();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f21545f..04a8265 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1387,7 +1387,7 @@
if (mTextActionMode != null) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
- hideFloatingToolbar();
+ hideFloatingToolbar(ActionMode.DEFAULT_HIDE_DURATION);
break;
case MotionEvent.ACTION_UP: // fall through
case MotionEvent.ACTION_CANCEL:
@@ -1396,10 +1396,10 @@
}
}
- private void hideFloatingToolbar() {
+ void hideFloatingToolbar(int duration) {
if (mTextActionMode != null) {
mTextView.removeCallbacks(mShowFloatingToolbar);
- mTextActionMode.hide(ActionMode.DEFAULT_HIDE_DURATION);
+ mTextActionMode.hide(duration);
}
}
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 33e6521..75fc538 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -486,7 +486,7 @@
if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
width = Math.max(width, myWidth - params.mLeft);
} else {
- width = Math.max(width, myWidth - params.mLeft - params.leftMargin);
+ width = Math.max(width, myWidth - params.mLeft + params.leftMargin);
}
} else {
if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 142412a..3f4ce44 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -68,9 +68,7 @@
public void startActionModeAsync(boolean adjustSelection) {
cancelAsyncTask();
- if (isNoOpTextClassifier() || !hasSelection()) {
- // No need to make an async call for a no-op TextClassifier.
- // Do not call the TextClassifier if there is no selection.
+ if (skipTextClassification()) {
startActionMode(null);
} else {
resetTextClassificationHelper(true /* resetSelectionTag */);
@@ -88,9 +86,7 @@
public void invalidateActionModeAsync() {
cancelAsyncTask();
- if (isNoOpTextClassifier() || !hasSelection()) {
- // No need to make an async call for a no-op TextClassifier.
- // Do not call the TextClassifier if there is no selection.
+ if (skipTextClassification()) {
invalidateActionMode(null);
} else {
resetTextClassificationHelper(false /* resetSelectionTag */);
@@ -132,13 +128,16 @@
mTextClassification = null;
}
- private boolean isNoOpTextClassifier() {
- return mEditor.getTextView().getTextClassifier() == TextClassifier.NO_OP;
- }
-
- private boolean hasSelection() {
+ private boolean skipTextClassification() {
final TextView textView = mEditor.getTextView();
- return textView.getSelectionEnd() > textView.getSelectionStart();
+ // No need to make an async call for a no-op TextClassifier.
+ final boolean noOpTextClassifier = textView.getTextClassifier() == TextClassifier.NO_OP;
+ // Do not call the TextClassifier if there is no selection.
+ final boolean noSelection = textView.getSelectionEnd() == textView.getSelectionStart();
+ // Do not call the TextClassifier if this is a password field.
+ final boolean password = textView.hasPasswordTransformationMethod()
+ || TextView.isPasswordInputType(textView.getInputType());
+ return noOpTextClassifier || noSelection || password;
}
private void startActionMode(@Nullable SelectionResult result) {
diff --git a/core/java/android/widget/TextInputTimePickerView.java b/core/java/android/widget/TextInputTimePickerView.java
index 11b7514d..0cf8faa 100644
--- a/core/java/android/widget/TextInputTimePickerView.java
+++ b/core/java/android/widget/TextInputTimePickerView.java
@@ -17,6 +17,7 @@
package android.widget;
import android.content.Context;
+import android.os.LocaleList;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextWatcher;
@@ -141,6 +142,9 @@
new InputFilter.LengthFilter(maxCharLength)});
mMinuteEditText.setFilters(new InputFilter[] {
new InputFilter.LengthFilter(maxCharLength)});
+ final LocaleList locales = mContext.getResources().getConfiguration().getLocales();
+ mHourEditText.setImeHintLocales(locales);
+ mMinuteEditText.setImeHintLocales(locales);
}
boolean validateInput() {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9a92489..69edbbb 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -374,6 +374,8 @@
private static final int KEY_DOWN_HANDLED_BY_KEY_LISTENER = 1;
private static final int KEY_DOWN_HANDLED_BY_MOVEMENT_METHOD = 2;
+ private static final int FLOATING_TOOLBAR_SELECT_ALL_REFRESH_DELAY = 500;
+
// System wide time for last cut, copy or text changed action.
static long sLastCutCopyOrTextChangedTime;
@@ -5674,7 +5676,7 @@
return mTransformation instanceof PasswordTransformationMethod;
}
- private static boolean isPasswordInputType(int inputType) {
+ static boolean isPasswordInputType(int inputType) {
final int variation =
inputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION);
return variation
@@ -11138,6 +11140,10 @@
}
boolean selectAllText() {
+ if (mEditor != null) {
+ // Hide the toolbar before changing the selection to avoid flickering.
+ mEditor.hideFloatingToolbar(FLOATING_TOOLBAR_SELECT_ALL_REFRESH_DELAY);
+ }
final int length = mText.length();
Selection.setSelection((Spannable) mText, 0, length);
return length > 0;
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index eda63b3..378826d 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -375,8 +375,15 @@
try {
int selectedPos = new ArrayList<ComponentName>(mTargetsDict.keySet())
.indexOf(componentName);
- logMetrics(selectedPos);
- if (selectedPos > 0) {
+ if (selectedPos >= 0 && mTargets != null) {
+ final float selectedProbability = getScore(componentName);
+ int order = 0;
+ for (ResolverTarget target : mTargets) {
+ if (target.getSelectProbability() > selectedProbability) {
+ order++;
+ }
+ }
+ logMetrics(order);
mRanker.train(mTargets, selectedPos);
} else {
if (DEBUG) {
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java
index 04819a5..2648604 100644
--- a/core/java/com/android/internal/colorextraction/ColorExtractor.java
+++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java
@@ -51,7 +51,7 @@
private WallpaperColors mLockColors;
public ColorExtractor(Context context) {
- this(context, new Tonal());
+ this(context, new Tonal(context));
}
@VisibleForTesting
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index e78ca38..dbc086c 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -19,15 +19,22 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WallpaperColors;
+import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.util.MathUtils;
import android.util.Range;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.graphics.ColorUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -49,9 +56,23 @@
public static final int MAIN_COLOR_DARK = 0xff212121;
public static final int SECONDARY_COLOR_DARK = 0xff000000;
+ private final TonalPalette mGreyPalette;
+ private final ArrayList<TonalPalette> mTonalPalettes;
+ private final ArrayList<ColorRange> mBlacklistedColors;
+
// Temporary variable to avoid allocations
private float[] mTmpHSL = new float[3];
+ public Tonal(Context context) {
+
+ ConfigParser parser = new ConfigParser(context);
+ mTonalPalettes = parser.getTonalPalettes();
+ mBlacklistedColors = parser.getBlacklistedColors();
+
+ mGreyPalette = mTonalPalettes.get(0);
+ mTonalPalettes.remove(0);
+ }
+
/**
* Grab colors from WallpaperColors and set them into GradientColors.
* Also applies the default gradient in case extraction fails.
@@ -220,7 +241,7 @@
if (DEBUG) {
Log.d(TAG, "Gradients: \n\tNormal " + outColorsNormal + "\n\tDark " + outColorsDark
- + "\n\tExtra dark: " + outColorsExtraDark);
+ + "\n\tExtra dark: " + outColorsExtraDark);
}
return true;
@@ -266,7 +287,8 @@
* @return true if color should be avoided
*/
private boolean isBlacklisted(float[] hsl) {
- for (ColorRange badRange: BLACKLISTED_COLORS) {
+ for (int i = mBlacklistedColors.size() - 1; i >= 0; i--) {
+ ColorRange badRange = mBlacklistedColors.get(i);
if (badRange.containsColor(hsl[0], hsl[1], hsl[2])) {
return true;
}
@@ -322,19 +344,25 @@
return minErrorIndex;
}
+ @VisibleForTesting
+ public List<ColorRange> getBlacklistedColors() {
+ return mBlacklistedColors;
+ }
+
@Nullable
- private static TonalPalette findTonalPalette(float h, float s) {
+ private TonalPalette findTonalPalette(float h, float s) {
// Fallback to a grey palette if the color is too desaturated.
// This avoids hue shifts.
if (s < 0.05f) {
- return GREY_PALETTE;
+ return mGreyPalette;
}
TonalPalette best = null;
float error = Float.POSITIVE_INFINITY;
- for (int i = 0; i < TONAL_PALETTES.length; i++) {
- final TonalPalette candidate = TONAL_PALETTES[i];
+ final int tonalPalettesCount = mTonalPalettes.size();
+ for (int i = 0; i < tonalPalettesCount; i++) {
+ final TonalPalette candidate = mTonalPalettes.get(i);
if (h >= candidate.minHue && h <= candidate.maxHue) {
best = candidate;
@@ -388,7 +416,6 @@
+ Arrays.toString(h) + " s: " + Arrays.toString(s) + " l: "
+ Arrays.toString(l));
}
-
this.h = h;
this.s = s;
this.l = l;
@@ -406,430 +433,6 @@
}
}
- // Data definition of Material Design tonal palettes
- // When the sort type is set to TONAL, these palettes are used to find
- // a best fit. Each palette is defined as 22 HSL colors
- private static final TonalPalette[] TONAL_PALETTES = {
- new TonalPalette(
- new float[] {1f, 1f, 0.991f, 0.991f, 0.9833333333333333f, 0f, 0f, 0f,
- 0.01134380453752181f, 0.015625000000000003f, 0.024193548387096798f,
- 0.027397260273972573f, 0.017543859649122865f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.8434782608695652f, 1f, 1f, 1f, 1f,
- 1f},
- new float[] {0.04f, 0.09f, 0.14f, 0.2f, 0.27450980392156865f,
- 0.34901960784313724f, 0.4235294117647059f, 0.5490196078431373f,
- 0.6254901960784314f, 0.6862745098039216f, 0.7568627450980392f,
- 0.8568627450980393f, 0.9254901960784314f}
- ),
- new TonalPalette(
- new float[] {0.638f, 0.638f, 0.6385767790262171f, 0.6301169590643275f,
- 0.6223958333333334f, 0.6151079136690647f, 0.6065400843881856f,
- 0.5986964618249534f, 0.5910746812386157f, 0.5833333333333334f,
- 0.5748031496062993f, 0.5582010582010583f},
- new float[] {1f, 1f, 1f, 1f, 0.9014084507042253f, 0.8128654970760234f,
- 0.7979797979797981f, 0.7816593886462883f, 0.778723404255319f, 1f, 1f,
- 1f},
- new float[] {0.05f, 0.12f, 0.17450980392156862f, 0.2235294117647059f,
- 0.2784313725490196f, 0.3352941176470588f, 0.388235294117647f,
- 0.44901960784313727f, 0.5392156862745098f, 0.6509803921568628f,
- 0.7509803921568627f, 0.8764705882352941f}
- ),
- new TonalPalette(
- new float[] {0.563f, 0.569f, 0.5666f, 0.5669934640522876f, 0.5748031496062993f,
- 0.5595238095238095f, 0.5473118279569893f, 0.5393258426966292f,
- 0.5315955766192734f, 0.524031007751938f, 0.5154711673699016f,
- 0.508080808080808f, 0.5f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.8847736625514403f, 1f, 1f,
- 1f},
- new float[] {0.07f, 0.12f, 0.16f, 0.2f, 0.24901960784313726f,
- 0.27450980392156865f, 0.30392156862745096f, 0.34901960784313724f,
- 0.4137254901960784f, 0.47647058823529415f, 0.5352941176470588f,
- 0.6764705882352942f, 0.8f}
- ),
- new TonalPalette(
- new float[] {0.508f, 0.511f, 0.508f, 0.508f, 0.5082304526748972f,
- 0.5069444444444444f, 0.5f, 0.5f, 0.5f, 0.48724954462659376f,
- 0.4800347222222222f, 0.4755134281200632f, 0.4724409448818897f,
- 0.4671052631578947f},
- new float[] {1f, 1f, 1f, 1f, 1f, 0.8888888888888887f, 0.9242424242424242f, 1f,
- 1f, 0.8133333333333332f, 0.7868852459016393f, 1f, 1f, 1f},
- new float[] {0.04f, 0.06f, 0.08f, 0.12f, 0.1588235294117647f,
- 0.21176470588235297f, 0.25882352941176473f, 0.3f, 0.34901960784313724f,
- 0.44117647058823534f, 0.5215686274509804f, 0.5862745098039216f,
- 0.7509803921568627f, 0.8509803921568627f}
- ),
- new TonalPalette(
- new float[] {0.333f, 0.333f, 0.333f, 0.3333333333333333f, 0.3333333333333333f,
- 0.34006734006734f, 0.34006734006734f, 0.34006734006734f,
- 0.34259259259259256f, 0.3475783475783476f, 0.34767025089605735f,
- 0.3467741935483871f, 0.3703703703703704f},
- new float[] {0.70f, 0.72f, 0.69f, 0.6703296703296703f, 0.728813559322034f,
- 0.5657142857142856f, 0.5076923076923077f, 0.3944223107569721f,
- 0.6206896551724138f, 0.8931297709923666f, 1f, 1f, 1f},
- new float[] {0.05f, 0.08f, 0.14f, 0.1784313725490196f, 0.23137254901960785f,
- 0.3431372549019608f, 0.38235294117647056f, 0.49215686274509807f,
- 0.6588235294117647f, 0.7431372549019608f, 0.8176470588235294f,
- 0.8784313725490196f, 0.9294117647058824f}
- ),
- new TonalPalette(
- new float[] {0.161f, 0.163f, 0.163f, 0.162280701754386f, 0.15032679738562088f,
- 0.15879265091863518f, 0.16236559139784948f, 0.17443868739205526f,
- 0.17824074074074076f, 0.18674698795180725f, 0.18692449355432778f,
- 0.1946778711484594f, 0.18604651162790695f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
- new float[] {0.05f, 0.08f, 0.11f, 0.14901960784313725f, 0.2f,
- 0.24901960784313726f, 0.30392156862745096f, 0.3784313725490196f,
- 0.4235294117647059f, 0.48823529411764705f, 0.6450980392156863f,
- 0.7666666666666666f, 0.8313725490196078f}
- ),
- new TonalPalette(
- new float[] {0.108f, 0.105f, 0.105f, 0.105f, 0.10619469026548674f,
- 0.11924686192468618f, 0.13046448087431692f, 0.14248366013071895f,
- 0.1506024096385542f, 0.16220238095238093f, 0.16666666666666666f,
- 0.16666666666666666f, 0.162280701754386f, 0.15686274509803924f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
- new float[] {0.17f, 0.22f, 0.28f, 0.35f, 0.44313725490196076f,
- 0.46862745098039216f, 0.47843137254901963f, 0.5f, 0.5117647058823529f,
- 0.5607843137254902f, 0.6509803921568628f, 0.7509803921568627f,
- 0.8509803921568627f, 0.9f}
- ),
- new TonalPalette(
- new float[] {0.036f, 0.036f, 0.036f, 0.036f, 0.03561253561253561f,
- 0.05098039215686275f, 0.07516339869281045f, 0.09477124183006536f,
- 0.1150326797385621f, 0.134640522875817f, 0.14640522875816991f,
- 0.1582397003745319f, 0.15773809523809523f, 0.15359477124183002f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
- new float[] {0.19f, 0.26f, 0.34f, 0.39f, 0.4588235294117647f, 0.5f, 0.5f, 0.5f,
- 0.5f, 0.5f, 0.5f, 0.6509803921568628f, 0.7803921568627451f, 0.9f}
- ),
- new TonalPalette(
- new float[] {0.955f, 0.961f, 0.958f, 0.9596491228070175f, 0.9593837535014005f,
- 0.9514767932489452f, 0.943859649122807f, 0.9396825396825397f,
- 0.9395424836601307f, 0.9393939393939394f, 0.9362745098039216f,
- 0.9754098360655739f, 0.9824561403508771f},
- new float[] {0.87f, 0.85f, 0.85f, 0.84070796460177f, 0.8206896551724138f,
- 0.7979797979797981f, 0.7661290322580644f, 0.9051724137931036f,
- 1f, 1f, 1f, 1f, 1f},
- new float[] {0.06f, 0.11f, 0.16f, 0.22156862745098038f, 0.2843137254901961f,
- 0.388235294117647f, 0.48627450980392156f, 0.5450980392156863f,
- 0.6f, 0.6764705882352942f, 0.8f, 0.8803921568627451f,
- 0.9254901960784314f}
- ),
- new TonalPalette(
- new float[] {0.866f, 0.855f, 0.841025641025641f, 0.8333333333333334f,
- 0.8285256410256411f, 0.821522309711286f, 0.8083333333333333f,
- 0.8046594982078853f, 0.8005822416302766f, 0.7842377260981912f,
- 0.7771084337349398f, 0.7747747747747749f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f,
- 0.737142857142857f, 0.6434108527131781f, 0.46835443037974644f},
- new float[] {0.05f, 0.08f, 0.12745098039215685f, 0.15490196078431373f,
- 0.20392156862745098f, 0.24901960784313726f, 0.3137254901960784f,
- 0.36470588235294116f, 0.44901960784313727f, 0.6568627450980392f,
- 0.7470588235294118f, 0.8450980392156863f}
- ),
- new TonalPalette(
- new float[] {0.925f, 0.93f, 0.938f, 0.947f, 0.955952380952381f,
- 0.9681069958847737f, 0.9760479041916167f, 0.9873563218390804f, 0f, 0f,
- 0.009057971014492771f, 0.026748971193415648f,
- 0.041666666666666616f, 0.05303030303030304f},
- new float[] {1f, 1f, 1f, 1f, 1f, 0.8350515463917526f, 0.6929460580912863f,
- 0.6387665198237885f, 0.6914893617021276f, 0.7583892617449666f,
- 0.8070175438596495f, 0.9310344827586209f, 1f, 1f},
- new float[] {0.10f, 0.13f, 0.17f, 0.2f, 0.27450980392156865f,
- 0.3803921568627451f, 0.4725490196078432f, 0.5549019607843138f,
- 0.6313725490196078f, 0.707843137254902f, 0.7764705882352941f,
- 0.8294117647058823f, 0.9058823529411765f, 0.9568627450980391f}
- ),
- new TonalPalette(
- new float[] {0.733f, 0.736f, 0.744f, 0.7514619883040936f, 0.7679738562091503f,
- 0.7802083333333333f, 0.7844311377245509f, 0.796875f,
- 0.8165618448637316f, 0.8487179487179487f, 0.8582375478927203f,
- 0.8562091503267975f, 0.8666666666666667f},
- new float[] {1f, 1f, 1f, 1f, 1f, 0.8163265306122449f, 0.6653386454183268f,
- 0.7547169811320753f, 0.929824561403509f, 0.9558823529411766f,
- 0.9560439560439562f, 1f, 1f},
- new float[] {0.07f, 0.12f, 0.17f, 0.2235294117647059f, 0.3f,
- 0.38431372549019605f, 0.492156862745098f, 0.5843137254901961f,
- 0.6647058823529411f, 0.7333333333333334f, 0.8215686274509804f, 0.9f,
- 0.9411764705882353f}
- ),
- new TonalPalette(
- new float[] {0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
- 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
- 0.6666666666666666f, 0.6666666666666666f, 0.6666666666666666f,
- 0.6666666666666666f, 0.6666666666666666f},
- new float[] {0.25f, 0.24590163934426232f, 0.17880794701986752f,
- 0.14606741573033713f, 0.13761467889908252f, 0.14893617021276592f,
- 0.16756756756756758f, 0.20312500000000017f, 0.26086956521739135f,
- 0.29999999999999966f, 0.5000000000000004f},
- new float[] {0.18f, 0.2392156862745098f, 0.296078431372549f,
- 0.34901960784313724f, 0.4274509803921569f, 0.5392156862745098f,
- 0.6372549019607843f, 0.7490196078431373f, 0.8196078431372549f,
- 0.8823529411764706f, 0.9372549019607843f}
- ),
- new TonalPalette(
- new float[] {0.938f, 0.944f, 0.952f, 0.961f, 0.9678571428571429f,
- 0.9944812362030905f, 0f, 0f,
- 0.0047348484848484815f, 0.00316455696202532f, 0f,
- 0.9980392156862745f, 0.9814814814814816f, 0.9722222222222221f},
- new float[] {1f, 1f, 1f, 1f, 1f, 0.7023255813953488f, 0.6638655462184874f,
- 0.6521739130434782f, 0.7719298245614035f, 0.8315789473684211f,
- 0.6867469879518071f, 0.7264957264957265f, 0.8181818181818182f,
- 0.8181818181818189f},
- new float[] {0.08f, 0.13f, 0.18f, 0.23f, 0.27450980392156865f,
- 0.4215686274509804f,
- 0.4666666666666667f, 0.503921568627451f, 0.5529411764705883f,
- 0.6274509803921569f, 0.6745098039215687f, 0.7705882352941176f,
- 0.892156862745098f, 0.9568627450980391f}
- ),
- new TonalPalette(
- new float[] {0.88f, 0.888f, 0.897f, 0.9052287581699346f, 0.9112021857923498f,
- 0.9270152505446624f, 0.9343137254901961f, 0.9391534391534391f,
- 0.9437984496124031f, 0.943661971830986f, 0.9438943894389439f,
- 0.9426229508196722f, 0.9444444444444444f},
- new float[] {1f, 1f, 1f, 1f, 0.8133333333333332f, 0.7927461139896375f,
- 0.7798165137614679f, 0.7777777777777779f, 0.8190476190476191f,
- 0.8255813953488372f, 0.8211382113821142f, 0.8133333333333336f,
- 0.8000000000000006f},
- new float[] {0.08f, 0.12f, 0.16f, 0.2f, 0.29411764705882354f,
- 0.3784313725490196f, 0.42745098039215684f, 0.4764705882352941f,
- 0.5882352941176471f, 0.6627450980392157f, 0.7588235294117647f,
- 0.8529411764705882f, 0.9411764705882353f}
- ),
- new TonalPalette(
- new float[] {0.669f, 0.680f, 0.6884057971014492f, 0.6974789915966387f,
- 0.7079889807162534f, 0.7154471544715447f, 0.7217741935483872f,
- 0.7274143302180687f, 0.7272727272727273f, 0.7258064516129031f,
- 0.7252252252252251f, 0.7333333333333333f},
- new float[] {0.81f, 0.81f, 0.8214285714285715f, 0.6878612716763006f,
- 0.6080402010050251f, 0.5774647887323943f, 0.5391304347826086f,
- 0.46724890829694316f, 0.4680851063829788f, 0.462686567164179f,
- 0.45679012345678977f, 0.4545454545454551f},
- new float[] {0.12f, 0.16f, 0.2196078431372549f, 0.33921568627450976f,
- 0.39019607843137255f, 0.4176470588235294f, 0.45098039215686275f,
- 0.5509803921568628f, 0.6313725490196078f, 0.7372549019607844f,
- 0.8411764705882353f, 0.9352941176470588f}
- ),
- new TonalPalette(
- new float[] {0.6470588235294118f, 0.6516666666666667f, 0.6464174454828661f,
- 0.6441441441441442f, 0.6432748538011696f, 0.6416666666666667f,
- 0.6402439024390243f, 0.6412429378531074f, 0.6435185185185186f,
- 0.6428571428571429f},
- new float[] {0.8095238095238095f, 0.6578947368421053f, 0.5721925133689839f,
- 0.5362318840579711f, 0.5f, 0.4424778761061947f, 0.44086021505376327f,
- 0.44360902255639095f, 0.4499999999999997f, 0.4375000000000006f},
- new float[] {0.16470588235294117f, 0.2980392156862745f, 0.36666666666666664f,
- 0.40588235294117647f, 0.44705882352941173f,
- 0.5568627450980392f, 0.6352941176470588f, 0.7392156862745098f,
- 0.8431372549019608f, 0.9372549019607843f}
- ),
- new TonalPalette(
- new float[] {0.469f, 0.46732026143790845f, 0.4718614718614719f,
- 0.4793650793650794f, 0.48071625344352614f, 0.4829683698296837f,
- 0.484375f, 0.4841269841269842f, 0.48444444444444457f,
- 0.48518518518518516f, 0.4907407407407408f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 0.6274509803921569f, 0.41832669322709176f,
- 0.41899441340782106f, 0.4128440366972478f, 0.4090909090909088f},
- new float[] {0.07f, 0.1f, 0.15098039215686274f, 0.20588235294117646f,
- 0.2372549019607843f, 0.26862745098039215f, 0.4f, 0.5078431372549019f,
- 0.6490196078431372f, 0.7862745098039216f, 0.9137254901960784f}
- ),
- new TonalPalette(
- new float[] {0.542f, 0.5444444444444444f, 0.5555555555555556f,
- 0.5555555555555556f, 0.553763440860215f, 0.5526315789473684f,
- 0.5555555555555556f, 0.5555555555555555f, 0.5555555555555556f,
- 0.5512820512820514f, 0.5666666666666667f},
- new float[] {0.25f, 0.24590163934426232f, 0.19148936170212766f,
- 0.1791044776119403f, 0.18343195266272191f, 0.18446601941747576f,
- 0.1538461538461539f, 0.15625000000000003f, 0.15328467153284678f,
- 0.15662650602409653f, 0.151515151515151f},
- new float[] {0.05f, 0.1196078431372549f, 0.1843137254901961f,
- 0.2627450980392157f,
- 0.33137254901960783f, 0.403921568627451f, 0.5411764705882354f,
- 0.6235294117647059f, 0.7313725490196079f, 0.8372549019607843f,
- 0.9352941176470588f}
- ),
- new TonalPalette(
- new float[] {0.022222222222222223f, 0.02469135802469136f, 0.031249999999999997f,
- 0.03947368421052631f, 0.04166666666666668f,
- 0.043650793650793655f, 0.04411764705882352f, 0.04166666666666652f,
- 0.04444444444444459f, 0.05555555555555529f},
- new float[] {0.33333333333333337f, 0.2783505154639175f, 0.2580645161290323f,
- 0.25675675675675674f, 0.2528735632183908f, 0.17500000000000002f,
- 0.15315315315315312f, 0.15189873417721522f,
- 0.15789473684210534f, 0.15789473684210542f},
- new float[] {0.08823529411764705f, 0.19019607843137254f, 0.2431372549019608f,
- 0.2901960784313725f, 0.3411764705882353f, 0.47058823529411764f,
- 0.5647058823529412f, 0.6901960784313725f, 0.8137254901960784f,
- 0.9254901960784314f}
- ),
- new TonalPalette(
- new float[] {0.027f, 0.03f, 0.038f, 0.044f, 0.050884955752212385f,
- 0.07254901960784313f, 0.0934640522875817f,
- 0.10457516339869281f, 0.11699346405228758f,
- 0.1255813953488372f, 0.1268939393939394f, 0.12533333333333332f,
- 0.12500000000000003f, 0.12777777777777777f},
- new float[] {1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f},
- new float[] {0.25f, 0.3f, 0.35f, 0.4f, 0.44313725490196076f, 0.5f, 0.5f, 0.5f,
- 0.5f, 0.5784313725490196f,
- 0.6549019607843137f, 0.7549019607843137f, 0.8509803921568627f,
- 0.9411764705882353f}
- )
- };
-
- private static final TonalPalette GREY_PALETTE = new TonalPalette(
- new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
- new float[]{0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f},
- new float[]{0.08f, 0.11f, 0.14901960784313725f, 0.2f, 0.2980392156862745f, 0.4f,
- 0.4980392156862745f, 0.6196078431372549f, 0.7176470588235294f,
- 0.8196078431372549f, 0.9176470588235294f, 0.9490196078431372f}
- );
-
- @SuppressWarnings("WeakerAccess")
- @VisibleForTesting
- public static final ColorRange[] BLACKLISTED_COLORS = new ColorRange[] {
-
- // Red
- new ColorRange(
- new Range<>(0f, 20f) /* H */,
- new Range<>(0.7f, 1f) /* S */,
- new Range<>(0.21f, 0.79f)) /* L */,
- new ColorRange(
- new Range<>(0f, 20f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.355f, 0.653f)),
-
- // Red Orange
- new ColorRange(
- new Range<>(20f, 40f),
- new Range<>(0.7f, 1f),
- new Range<>(0.28f, 0.643f)),
- new ColorRange(
- new Range<>(20f, 40f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.414f, 0.561f)),
- new ColorRange(
- new Range<>(20f, 40f),
- new Range<>(0f, 3f),
- new Range<>(0.343f, 0.584f)),
-
- // Orange
- new ColorRange(
- new Range<>(40f, 60f),
- new Range<>(0.7f, 1f),
- new Range<>(0.173f, 0.349f)),
- new ColorRange(
- new Range<>(40f, 60f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.233f, 0.427f)),
- new ColorRange(
- new Range<>(40f, 60f),
- new Range<>(0f, 0.3f),
- new Range<>(0.231f, 0.484f)),
-
- // Yellow 60
- new ColorRange(
- new Range<>(60f, 80f),
- new Range<>(0.7f, 1f),
- new Range<>(0.488f, 0.737f)),
- new ColorRange(
- new Range<>(60f, 80f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.673f, 0.837f)),
-
- // Yellow Green 80
- new ColorRange(
- new Range<>(80f, 100f),
- new Range<>(0.7f, 1f),
- new Range<>(0.469f, 0.61f)),
-
- // Yellow green 100
- new ColorRange(
- new Range<>(100f, 120f),
- new Range<>(0.7f, 1f),
- new Range<>(0.388f, 0.612f)),
- new ColorRange(
- new Range<>(100f, 120f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.424f, 0.541f)),
-
- // Green
- new ColorRange(
- new Range<>(120f, 140f),
- new Range<>(0.7f, 1f),
- new Range<>(0.375f, 0.52f)),
- new ColorRange(
- new Range<>(120f, 140f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.435f, 0.524f)),
-
- // Green Blue 140
- new ColorRange(
- new Range<>(140f, 160f),
- new Range<>(0.7f, 1f),
- new Range<>(0.496f, 0.641f)),
-
- // Seafoam
- new ColorRange(
- new Range<>(160f, 180f),
- new Range<>(0.7f, 1f),
- new Range<>(0.496f, 0.567f)),
-
- // Cyan
- new ColorRange(
- new Range<>(180f, 200f),
- new Range<>(0.7f, 1f),
- new Range<>(0.52f, 0.729f)),
-
- // Blue
- new ColorRange(
- new Range<>(220f, 240f),
- new Range<>(0.7f, 1f),
- new Range<>(0.396f, 0.571f)),
- new ColorRange(
- new Range<>(220f, 240f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.425f, 0.551f)),
-
- // Blue Purple 240
- new ColorRange(
- new Range<>(240f, 260f),
- new Range<>(0.7f, 1f),
- new Range<>(0.418f, 0.639f)),
- new ColorRange(
- new Range<>(220f, 240f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.441f, 0.576f)),
-
- // Blue Purple 260
- new ColorRange(
- new Range<>(260f, 280f),
- new Range<>(0.3f, 1f), // Bigger range
- new Range<>(0.461f, 0.553f)),
-
- // Fuchsia
- new ColorRange(
- new Range<>(300f, 320f),
- new Range<>(0.7f, 1f),
- new Range<>(0.484f, 0.588f)),
- new ColorRange(
- new Range<>(300f, 320f),
- new Range<>(0.3f, 0.7f),
- new Range<>(0.48f, 0.592f)),
-
- // Pink
- new ColorRange(
- new Range<>(320f, 340f),
- new Range<>(0.7f, 1f),
- new Range<>(0.466f, 0.629f)),
-
- // Soft red
- new ColorRange(
- new Range<>(340f, 360f),
- new Range<>(0.7f, 1f),
- new Range<>(0.437f, 0.596f))
- };
-
/**
* Representation of an HSL color range.
* <ul>
@@ -874,4 +477,124 @@
return String.format("H: %s, S: %s, L %s", mHue, mSaturation, mLightness);
}
}
-}
+
+ @VisibleForTesting
+ public static class ConfigParser {
+ private final ArrayList<TonalPalette> mTonalPalettes;
+ private final ArrayList<ColorRange> mBlacklistedColors;
+
+ public ConfigParser(Context context) {
+ mTonalPalettes = new ArrayList<>();
+ mBlacklistedColors = new ArrayList<>();
+
+ // Load all palettes and the blacklist from an XML.
+ try {
+ XmlPullParser parser = context.getResources().getXml(R.xml.color_extraction);
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_DOCUMENT ||
+ eventType == XmlPullParser.END_TAG) {
+ // just skip
+ } else if (eventType == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ if (tagName.equals("palettes")) {
+ parsePalettes(parser);
+ } else if (tagName.equals("blacklist")) {
+ parseBlacklist(parser);
+ }
+ } else {
+ throw new XmlPullParserException("Invalid XML event " + eventType + " - "
+ + parser.getName(), parser, null);
+ }
+ eventType = parser.next();
+ }
+ } catch (XmlPullParserException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public ArrayList<TonalPalette> getTonalPalettes() {
+ return mTonalPalettes;
+ }
+
+ public ArrayList<ColorRange> getBlacklistedColors() {
+ return mBlacklistedColors;
+ }
+
+ private void parseBlacklist(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ parser.require(XmlPullParser.START_TAG, null, "blacklist");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ // Starts by looking for the entry tag
+ if (name.equals("range")) {
+ mBlacklistedColors.add(readRange(parser));
+ parser.next();
+ } else {
+ throw new XmlPullParserException("Invalid tag: " + name, parser, null);
+ }
+ }
+ }
+
+ private ColorRange readRange(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ parser.require(XmlPullParser.START_TAG, null, "range");
+ float[] h = readFloatArray(parser.getAttributeValue(null, "h"));
+ float[] s = readFloatArray(parser.getAttributeValue(null, "s"));
+ float[] l = readFloatArray(parser.getAttributeValue(null, "l"));
+
+ if (h == null || s == null || l == null) {
+ throw new XmlPullParserException("Incomplete range tag.", parser, null);
+ }
+
+ return new ColorRange(new Range<>(h[0], h[1]), new Range<>(s[0], s[1]),
+ new Range<>(l[0], l[1]));
+ }
+
+ private void parsePalettes(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ parser.require(XmlPullParser.START_TAG, null, "palettes");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ // Starts by looking for the entry tag
+ if (name.equals("palette")) {
+ mTonalPalettes.add(readPalette(parser));
+ parser.next();
+ } else {
+ throw new XmlPullParserException("Invalid tag: " + name);
+ }
+ }
+ }
+
+ private TonalPalette readPalette(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ parser.require(XmlPullParser.START_TAG, null, "palette");
+
+ float[] h = readFloatArray(parser.getAttributeValue(null, "h"));
+ float[] s = readFloatArray(parser.getAttributeValue(null, "s"));
+ float[] l = readFloatArray(parser.getAttributeValue(null, "l"));
+
+ if (h == null || s == null || l == null) {
+ throw new XmlPullParserException("Incomplete range tag.", parser, null);
+ }
+
+ return new TonalPalette(h, s, l);
+ }
+
+ private float[] readFloatArray(String attributeValue)
+ throws IOException, XmlPullParserException {
+ String[] tokens = attributeValue.replaceAll(" ", "").replaceAll("\n", "").split(",");
+ float[] numbers = new float[tokens.length];
+ for (int i = 0; i < tokens.length; i++) {
+ numbers[i] = Float.parseFloat(tokens[i]);
+ }
+ return numbers;
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index ebea1a4..04874bd 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -28,6 +28,7 @@
import android.graphics.Point;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.CancellationSignal;
import android.os.FileObserver;
import android.os.FileUtils;
@@ -68,6 +69,8 @@
private Handler mHandler;
+ private static final String MIMETYPE_PDF = "application/pdf";
+
protected abstract File getFileForDocId(String docId, boolean visible)
throws FileNotFoundException;
@@ -387,6 +390,13 @@
String documentId, Point sizeHint, CancellationSignal signal)
throws FileNotFoundException {
final File file = getFileForDocId(documentId);
+ if (getTypeForFile(file).equals(MIMETYPE_PDF)) {
+ try {
+ return PdfUtils.openPdfThumbnail(file, sizeHint);
+ } catch (Exception e) {
+ Log.v(TAG, "Could not load PDF's thumbnail", e);
+ }
+ }
return DocumentsContract.openImageThumbnail(file);
}
@@ -416,7 +426,10 @@
final String mimeType = getTypeForFile(file);
final String displayName = file.getName();
- if (mimeType.startsWith("image/")) {
+ // As of right now, we aren't sure on the performance affect of loading all PDF Thumbnails
+ // Until a solution is found, it will be behind a debuggable flag.
+ if (mimeType.startsWith("image/")
+ || (mimeType.equals(MIMETYPE_PDF) && Build.IS_DEBUGGABLE)) {
flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
}
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 9c361b3..e923223 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -16,11 +16,14 @@
package com.android.internal.content;
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.os.storage.VolumeInfo.ID_PRIVATE_INTERNAL;
+
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageParser.PackageLite;
import android.os.Environment;
@@ -39,21 +42,19 @@
import com.android.internal.annotations.VisibleForTesting;
+import libcore.io.IoUtils;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Objects;
+import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
-import libcore.io.IoUtils;
-
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.os.storage.VolumeInfo.ID_PRIVATE_INTERNAL;
-
/**
* Constants used internally between the PackageManager
* and media container service transports.
@@ -358,7 +359,7 @@
public boolean fitsOnInternalStorage(Context context, SessionParams params)
throws IOException {
StorageManager storage = getStorageManager(context);
- File target = getDataDirectory();
+ final UUID target = storage.getUuidForPath(getDataDirectory());
return (params.sizeBytes <= storage.getAllocatableBytes(target,
translateAllocateFlags(params.installFlags)));
}
@@ -466,7 +467,8 @@
boolean isInternalStorage = ID_PRIVATE_INTERNAL.equals(vol.id);
if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()
&& (!isInternalStorage || allow3rdPartyOnInternal)) {
- final long availBytes = storageManager.getAllocatableBytes(new File(vol.path),
+ final UUID target = storageManager.getUuidForPath(new File(vol.path));
+ final long availBytes = storageManager.getAllocatableBytes(target,
translateAllocateFlags(params.installFlags));
if (availBytes >= params.sizeBytes) {
allCandidates.add(vol.fsUuid);
@@ -523,7 +525,7 @@
public static boolean fitsOnInternal(Context context, SessionParams params) throws IOException {
final StorageManager storage = context.getSystemService(StorageManager.class);
- final File target = Environment.getDataDirectory();
+ final UUID target = storage.getUuidForPath(Environment.getDataDirectory());
return (params.sizeBytes <= storage.getAllocatableBytes(target,
translateAllocateFlags(params.installFlags)));
}
diff --git a/core/java/com/android/internal/content/PdfUtils.java b/core/java/com/android/internal/content/PdfUtils.java
new file mode 100644
index 0000000..1716d42
--- /dev/null
+++ b/core/java/com/android/internal/content/PdfUtils.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.content;
+
+import android.annotation.Nullable;
+import android.content.res.AssetFileDescriptor;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.pdf.PdfRenderer;
+import android.os.AsyncTask;
+import android.os.ParcelFileDescriptor;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Utils class for extracting PDF Thumbnails
+ */
+public final class PdfUtils {
+
+ private PdfUtils() {
+ }
+
+ /**
+ * Returns the front page of the pdf as a thumbnail
+ * @param file Given PDF File
+ * @param size Cropping of the front page.
+ * @return AssetFileDescriptor containing the thumbnail as a bitmap.
+ * @throws IOException if the file isn't a pdf or if the file doesn't exist.
+ */
+ public static @Nullable AssetFileDescriptor openPdfThumbnail(File file, Point size)
+ throws IOException {
+ // Create the bitmap of the PDF's first page
+ ParcelFileDescriptor pdfDescriptor =
+ ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+ PdfRenderer renderer = new PdfRenderer(pdfDescriptor);
+ PdfRenderer.Page frontPage = renderer.openPage(0);
+ Bitmap thumbnail = Bitmap.createBitmap(size.x, size.y,
+ Bitmap.Config.ARGB_8888);
+ frontPage.render(thumbnail, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
+
+ // Create an AssetFileDescriptor that contains the Bitmap's information
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ // Quality is an integer that determines how much compression is used.
+ // However, this integer is ignored when using the PNG format
+ int quality = 100;
+ // The use of Bitmap.CompressFormat.JPEG leads to a black PDF background on the thumbnail
+ thumbnail.compress(Bitmap.CompressFormat.PNG, quality, out);
+
+ final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+
+ final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createReliablePipe();
+ new AsyncTask<Object, Object, Object>() {
+ @Override
+ protected Object doInBackground(Object... params) {
+ final FileOutputStream fos = new FileOutputStream(fds[1].getFileDescriptor());
+ try {
+ Streams.copy(in, fos);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ IoUtils.closeQuietly(fds[1]);
+ try {
+ pdfDescriptor.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ pdfDescriptor.close();
+ return new AssetFileDescriptor(fds[0], 0, AssetFileDescriptor.UNKNOWN_LENGTH);
+ }
+
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index fa23e40..c7f619d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -119,7 +119,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 160 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 161 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS;
@@ -5637,6 +5637,7 @@
StopwatchTimer mFlashlightTurnedOnTimer;
StopwatchTimer mCameraTurnedOnTimer;
StopwatchTimer mForegroundActivityTimer;
+ StopwatchTimer mForegroundServiceTimer;
/** Total time spent by the uid holding any partial wakelocks. */
DualTimer mAggregatedPartialWakelockTimer;
DualTimer mBluetoothScanTimer;
@@ -5647,6 +5648,8 @@
int mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
StopwatchTimer[] mProcessStateTimer;
+ boolean mInForegroundService = false;
+
BatchTimer mVibratorOnTimer;
Counter[] mUserActivityCounters;
@@ -6119,6 +6122,14 @@
return mForegroundActivityTimer;
}
+ public StopwatchTimer createForegroundServiceTimerLocked() {
+ if (mForegroundServiceTimer == null) {
+ mForegroundServiceTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ FOREGROUND_SERVICE, null, mBsi.mOnBatteryTimeBase);
+ }
+ return mForegroundServiceTimer;
+ }
+
public DualTimer createAggregatedPartialWakelockTimerLocked() {
if (mAggregatedPartialWakelockTimer == null) {
mAggregatedPartialWakelockTimer = new DualTimer(mBsi.mClocks, this,
@@ -6207,6 +6218,16 @@
}
}
+ public void noteForegroundServiceResumedLocked(long elapsedRealtimeMs) {
+ createForegroundServiceTimerLocked().startRunningLocked(elapsedRealtimeMs);
+ }
+
+ public void noteForegroundServicePausedLocked(long elapsedRealtimeMs) {
+ if (mForegroundServiceTimer != null) {
+ mForegroundServiceTimer.stopRunningLocked(elapsedRealtimeMs);
+ }
+ }
+
public BatchTimer createVibratorOnTimerLocked() {
if (mVibratorOnTimer == null) {
mVibratorOnTimer = new BatchTimer(mBsi.mClocks, Uid.this, VIBRATOR_ON,
@@ -6335,6 +6356,11 @@
}
@Override
+ public Timer getForegroundServiceTimer() {
+ return mForegroundServiceTimer;
+ }
+
+ @Override
public Timer getBluetoothScanTimer() {
return mBluetoothScanTimer;
}
@@ -6618,6 +6644,7 @@
active |= !resetTimerIfNotNull(mFlashlightTurnedOnTimer, false);
active |= !resetTimerIfNotNull(mCameraTurnedOnTimer, false);
active |= !resetTimerIfNotNull(mForegroundActivityTimer, false);
+ active |= !resetTimerIfNotNull(mForegroundServiceTimer, false);
active |= !resetTimerIfNotNull(mAggregatedPartialWakelockTimer, false);
active |= !resetTimerIfNotNull(mBluetoothScanTimer, false);
active |= !resetTimerIfNotNull(mBluetoothUnoptimizedScanTimer, false);
@@ -6817,6 +6844,10 @@
mForegroundActivityTimer.detach();
mForegroundActivityTimer = null;
}
+ if (mForegroundServiceTimer != null) {
+ mForegroundServiceTimer.detach();
+ mForegroundServiceTimer = null;
+ }
if (mAggregatedPartialWakelockTimer != null) {
mAggregatedPartialWakelockTimer.detach();
mAggregatedPartialWakelockTimer = null;
@@ -7026,6 +7057,12 @@
} else {
out.writeInt(0);
}
+ if (mForegroundServiceTimer != null) {
+ out.writeInt(1);
+ mForegroundServiceTimer.writeToParcel(out, elapsedRealtimeUs);
+ } else {
+ out.writeInt(0);
+ }
if (mAggregatedPartialWakelockTimer != null) {
out.writeInt(1);
mAggregatedPartialWakelockTimer.writeToParcel(out, elapsedRealtimeUs);
@@ -7305,6 +7342,12 @@
mForegroundActivityTimer = null;
}
if (in.readInt() != 0) {
+ mForegroundServiceTimer = new StopwatchTimer(mBsi.mClocks, Uid.this,
+ FOREGROUND_SERVICE, null, mBsi.mOnBatteryTimeBase, in);
+ } else {
+ mForegroundServiceTimer = null;
+ }
+ if (in.readInt() != 0) {
mAggregatedPartialWakelockTimer = new DualTimer(mBsi.mClocks, this,
AGGREGATED_WAKE_TYPE_PARTIAL, null,
mBsi.mOnBatteryScreenOffTimeBase, mOnBatteryScreenOffBackgroundTimeBase,
@@ -8350,6 +8393,9 @@
public void updateUidProcessStateLocked(int procState) {
int uidRunningState;
+ // Make special note of Foreground Services
+ final boolean userAwareService =
+ (procState == ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
uidRunningState = ActivityManager.PROCESS_STATE_NONEXISTENT;
} else if (procState == ActivityManager.PROCESS_STATE_TOP) {
@@ -8368,24 +8414,37 @@
uidRunningState = PROCESS_STATE_CACHED;
}
- if (mProcessState == uidRunningState) return;
+ if (mProcessState == uidRunningState && userAwareService == mInForegroundService) {
+ return;
+ }
final long elapsedRealtimeMs = mBsi.mClocks.elapsedRealtime();
- final long uptimeMs = mBsi.mClocks.uptimeMillis();
+ if (mProcessState != uidRunningState) {
+ final long uptimeMs = mBsi.mClocks.uptimeMillis();
- if (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
- mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtimeMs);
- }
- mProcessState = uidRunningState;
- if (uidRunningState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
- if (mProcessStateTimer[uidRunningState] == null) {
- makeProcessState(uidRunningState, null);
+ if (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtimeMs);
}
- mProcessStateTimer[uidRunningState].startRunningLocked(elapsedRealtimeMs);
+ mProcessState = uidRunningState;
+ if (uidRunningState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ if (mProcessStateTimer[uidRunningState] == null) {
+ makeProcessState(uidRunningState, null);
+ }
+ mProcessStateTimer[uidRunningState].startRunningLocked(elapsedRealtimeMs);
+ }
+
+ updateOnBatteryBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000);
+ updateOnBatteryScreenOffBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000);
}
- updateOnBatteryBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000);
- updateOnBatteryScreenOffBgTimeBase(uptimeMs * 1000, elapsedRealtimeMs * 1000);
+ if (userAwareService != mInForegroundService) {
+ if (userAwareService) {
+ noteForegroundServiceResumedLocked(elapsedRealtimeMs);
+ } else {
+ noteForegroundServicePausedLocked(elapsedRealtimeMs);
+ }
+ mInForegroundService = userAwareService;
+ }
}
/** Whether to consider Uid to be in the background for background timebase purposes. */
@@ -11610,6 +11669,9 @@
u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
+ u.createForegroundServiceTimerLocked().readSummaryFromParcelLocked(in);
+ }
+ if (in.readInt() != 0) {
u.createAggregatedPartialWakelockTimerLocked().readSummaryFromParcelLocked(in);
}
if (in.readInt() != 0) {
@@ -12021,6 +12083,12 @@
} else {
out.writeInt(0);
}
+ if (u.mForegroundServiceTimer != null) {
+ out.writeInt(1);
+ u.mForegroundServiceTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ } else {
+ out.writeInt(0);
+ }
if (u.mAggregatedPartialWakelockTimer != null) {
out.writeInt(1);
u.mAggregatedPartialWakelockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index a7fdb27..dbb6e93 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -21,13 +21,16 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArraySet;
+import android.util.ExceptionUtils;
+
+import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import java.util.function.Function;
+import java.util.function.*;
import java.util.stream.Stream;
/**
@@ -58,6 +61,32 @@
}
/**
+ * @see #filter(List, java.util.function.Predicate)
+ */
+ public static @NonNull <T> Set<T> filter(@Nullable Set<T> set,
+ java.util.function.Predicate<? super T> predicate) {
+ if (set == null || set.size() == 0) return Collections.emptySet();
+ ArraySet<T> result = null;
+ if (set instanceof ArraySet) {
+ ArraySet<T> arraySet = (ArraySet<T>) set;
+ int size = arraySet.size();
+ for (int i = 0; i < size; i++) {
+ final T item = arraySet.valueAt(i);
+ if (predicate.test(item)) {
+ result = ArrayUtils.add(result, item);
+ }
+ }
+ } else {
+ for (T item : set) {
+ if (predicate.test(item)) {
+ result = ArrayUtils.add(result, item);
+ }
+ }
+ }
+ return emptyIfNull(result);
+ }
+
+ /**
* Returns a list of items resulting from applying the given function to each element of the
* provided list.
*
@@ -77,6 +106,27 @@
}
/**
+ * @see #map(List, Function)
+ */
+ public static @NonNull <I, O> Set<O> map(@Nullable Set<I> cur,
+ Function<? super I, ? extends O> f) {
+ if (isEmpty(cur)) return Collections.emptySet();
+ ArraySet<O> result = new ArraySet<>();
+ if (cur instanceof ArraySet) {
+ ArraySet<I> arraySet = (ArraySet<I>) cur;
+ int size = arraySet.size();
+ for (int i = 0; i < size; i++) {
+ result.add(f.apply(arraySet.valueAt(i)));
+ }
+ } else {
+ for (I item : cur) {
+ result.add(f.apply(item));
+ }
+ }
+ return result;
+ }
+
+ /**
* {@link #map(List, Function)} + {@link #filter(List, java.util.function.Predicate)}
*
* Calling this is equivalent (but more memory efficient) to:
@@ -180,6 +230,17 @@
}
/**
+ * @see #add(List, Object)
+ */
+ public static @NonNull <T> Set<T> add(@Nullable Set<T> cur, T val) {
+ if (cur == null || cur == Collections.emptySet()) {
+ cur = new ArraySet<>();
+ }
+ cur.add(val);
+ return cur;
+ }
+
+ /**
* Similar to {@link List#remove}, but with support for list values of {@code null} and
* {@link Collections#emptyList}
*/
@@ -192,9 +253,52 @@
}
/**
+ * @see #remove(List, Object)
+ */
+ public static @NonNull <T> Set<T> remove(@Nullable Set<T> cur, T val) {
+ if (isEmpty(cur)) {
+ return emptyIfNull(cur);
+ }
+ cur.remove(val);
+ return cur;
+ }
+
+ /**
* @return a list that will not be affected by mutations to the given original list.
*/
public static @NonNull <T> List<T> copyOf(@Nullable List<T> cur) {
return isEmpty(cur) ? Collections.emptyList() : new ArrayList<>(cur);
}
+
+ /**
+ * @return a list that will not be affected by mutations to the given original list.
+ */
+ public static @NonNull <T> Set<T> copyOf(@Nullable Set<T> cur) {
+ return isEmpty(cur) ? Collections.emptySet() : new ArraySet<>(cur);
+ }
+
+ /**
+ * Applies {@code action} to each element in {@code cur}
+ *
+ * This avoids creating an iterator if the given set is an {@link ArraySet}
+ */
+ public static <T> void forEach(@Nullable Set<T> cur, @Nullable ThrowingConsumer<T> action) {
+ if (cur == null || action == null) return;
+ int size = cur.size();
+ if (size == 0) return;
+ try {
+ if (cur instanceof ArraySet) {
+ ArraySet<T> arraySet = (ArraySet<T>) cur;
+ for (int i = 0; i < size; i++) {
+ action.accept(arraySet.valueAt(i));
+ }
+ } else {
+ for (T t : cur) {
+ action.accept(t);
+ }
+ }
+ } catch (Exception e) {
+ throw ExceptionUtils.propagate(e);
+ }
+ }
}
diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java
index 9aeb041..cdef97e 100644
--- a/core/java/com/android/internal/util/FunctionalUtils.java
+++ b/core/java/com/android/internal/util/FunctionalUtils.java
@@ -45,4 +45,15 @@
public interface ThrowingSupplier<T> {
T get() throws Exception;
}
+
+ /**
+ * An equivalent of {@link java.util.function.Consumer} that allows throwing checked exceptions
+ *
+ * This can be used to specify a lambda argument without forcing all the checked exceptions
+ * to be handled within it
+ */
+ @FunctionalInterface
+ public interface ThrowingConsumer<T> {
+ void accept(T t) throws Exception;
+ }
}
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index ff211b6..497e7b0 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -295,6 +295,8 @@
*/
private static final class FloatingToolbarVisibilityHelper {
+ private static final long MIN_SHOW_DURATION_FOR_MOVE_HIDE = 500;
+
private final FloatingToolbar mToolbar;
private boolean mHideRequested;
@@ -304,6 +306,8 @@
private boolean mActive;
+ private long mLastShowTime;
+
public FloatingToolbarVisibilityHelper(FloatingToolbar toolbar) {
mToolbar = Preconditions.checkNotNull(toolbar);
}
@@ -327,7 +331,13 @@
}
public void setMoving(boolean moving) {
- mMoving = moving;
+ // Avoid unintended flickering by allowing the toolbar to show long enough before
+ // triggering the 'moving' flag - which signals a hide.
+ final boolean showingLongEnough =
+ System.currentTimeMillis() - mLastShowTime > MIN_SHOW_DURATION_FOR_MOVE_HIDE;
+ if (!moving || showingLongEnough) {
+ mMoving = moving;
+ }
}
public void setOutOfBounds(boolean outOfBounds) {
@@ -347,6 +357,7 @@
mToolbar.hide();
} else {
mToolbar.show();
+ mLastShowTime = System.currentTimeMillis();
}
}
}
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index 2cf58d7..18990cf 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -143,7 +143,6 @@
try {
return FileUtils.readTextFile(lastHeaderFile, 0, null);
} catch (IOException e) {
- Slog.e(TAG, "Error reading " + lastHeaderFile, e);
return null;
}
}
@@ -218,6 +217,8 @@
"/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG");
addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
"/sys/fs/pstore/console-ramoops", -LOG_SIZE, "SYSTEM_LAST_KMSG");
+ addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
+ "/sys/fs/pstore/console-ramoops-0", -LOG_SIZE, "SYSTEM_LAST_KMSG");
addFileToDropBox(db, timestamps, headers, "/cache/recovery/log", -LOG_SIZE,
"SYSTEM_RECOVERY_LOG");
addFileToDropBox(db, timestamps, headers, "/cache/recovery/last_kmsg",
@@ -303,6 +304,10 @@
if (fileTime <= 0) {
file = new File("/sys/fs/pstore/console-ramoops");
fileTime = file.lastModified();
+ if (fileTime <= 0) {
+ file = new File("/sys/fs/pstore/console-ramoops-0");
+ fileTime = file.lastModified();
+ }
}
if (fileTime <= 0) return; // File does not exist
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index b936973..3ecbcc3 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -985,6 +985,16 @@
}
}
+ static jfloat getStrikeThruPosition(jlong paintHandle, jlong typefaceHandle) {
+ const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize();
+ return SkScalarToFloat(Paint::kStdStrikeThru_Top * textSize);
+ }
+
+ static jfloat getStrikeThruThickness(jlong paintHandle, jlong typefaceHandle) {
+ const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize();
+ return SkScalarToFloat(Paint::kStdStrikeThru_Thickness * textSize);
+ }
+
static void setShadowLayer(jlong paintHandle, jfloat radius,
jfloat dx, jfloat dy, jint color) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
@@ -1098,6 +1108,8 @@
{"nDescent","(JJ)F", (void*) PaintGlue::descent},
{"nGetUnderlinePosition","(JJ)F", (void*) PaintGlue::getUnderlinePosition},
{"nGetUnderlineThickness","(JJ)F", (void*) PaintGlue::getUnderlineThickness},
+ {"nGetStrikeThruPosition","(JJ)F", (void*) PaintGlue::getStrikeThruPosition},
+ {"nGetStrikeThruThickness","(JJ)F", (void*) PaintGlue::getStrikeThruThickness},
{"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer},
{"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer}
};
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 16a9230..6c2b460 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -81,14 +81,27 @@
HEAP_GL,
HEAP_OTHER_MEMTRACK,
+ // Dalvik extra sections (heap).
HEAP_DALVIK_NORMAL,
HEAP_DALVIK_LARGE,
- HEAP_DALVIK_LINEARALLOC,
- HEAP_DALVIK_ACCOUNTING,
- HEAP_DALVIK_CODE_CACHE,
HEAP_DALVIK_ZYGOTE,
HEAP_DALVIK_NON_MOVING,
- HEAP_DALVIK_INDIRECT_REFERENCE_TABLE,
+
+ // Dalvik other extra sections.
+ HEAP_DALVIK_OTHER_LINEARALLOC,
+ HEAP_DALVIK_OTHER_ACCOUNTING,
+ HEAP_DALVIK_OTHER_CODE_CACHE,
+ HEAP_DALVIK_OTHER_COMPILER_METADATA,
+ HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE,
+
+ // Boot vdex / app dex / app vdex
+ HEAP_DEX_BOOT_VDEX,
+ HEAP_DEX_APP_DEX,
+ HEAP_DEX_APP_VDEX,
+
+ // App art, boot art.
+ HEAP_ART_APP,
+ HEAP_ART_BOOT,
_NUM_HEAP,
_NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1,
@@ -297,15 +310,30 @@
whichHeap = HEAP_TTF;
is_swappable = true;
} else if ((nameLen > 4 && strstr(name, ".dex") != NULL) ||
- (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0) ||
- (nameLen > 5 && strcmp(name+nameLen-5, ".vdex") == 0)) {
+ (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) {
whichHeap = HEAP_DEX;
+ subHeap = HEAP_DEX_APP_DEX;
+ is_swappable = true;
+ } else if (nameLen > 5 && strcmp(name+nameLen-5, ".vdex") == 0) {
+ whichHeap = HEAP_DEX;
+ // Handle system@framework@boot* and system/framework/boot*
+ if (strstr(name, "@boot") != NULL || strstr(name, "/boot") != NULL) {
+ subHeap = HEAP_DEX_BOOT_VDEX;
+ } else {
+ subHeap = HEAP_DEX_APP_VDEX;
+ }
is_swappable = true;
} else if (nameLen > 4 && strcmp(name+nameLen-4, ".oat") == 0) {
whichHeap = HEAP_OAT;
is_swappable = true;
} else if (nameLen > 4 && strcmp(name+nameLen-4, ".art") == 0) {
whichHeap = HEAP_ART;
+ // Handle system@framework@boot* and system/framework/boot*
+ if (strstr(name, "@boot") != NULL || strstr(name, "/boot") != NULL) {
+ subHeap = HEAP_ART_BOOT;
+ } else {
+ subHeap = HEAP_ART_APP;
+ }
is_swappable = true;
} else if (strncmp(name, "/dev/", 5) == 0) {
if (strncmp(name, "/dev/kgsl-3d0", 13) == 0) {
@@ -314,7 +342,7 @@
if (strncmp(name, "/dev/ashmem/dalvik-", 19) == 0) {
whichHeap = HEAP_DALVIK_OTHER;
if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) {
- subHeap = HEAP_DALVIK_LINEARALLOC;
+ subHeap = HEAP_DALVIK_OTHER_LINEARALLOC;
} else if ((strstr(name, "/dev/ashmem/dalvik-alloc space") == name) ||
(strstr(name, "/dev/ashmem/dalvik-main space") == name)) {
// This is the regular Dalvik heap.
@@ -332,13 +360,14 @@
whichHeap = HEAP_DALVIK;
subHeap = HEAP_DALVIK_ZYGOTE;
} else if (strstr(name, "/dev/ashmem/dalvik-indirect ref") == name) {
- subHeap = HEAP_DALVIK_INDIRECT_REFERENCE_TABLE;
+ subHeap = HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE;
} else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name ||
- strstr(name, "/dev/ashmem/dalvik-data-code-cache") == name ||
- strstr(name, "/dev/ashmem/dalvik-CompilerMetadata") == name) {
- subHeap = HEAP_DALVIK_CODE_CACHE;
+ strstr(name, "/dev/ashmem/dalvik-data-code-cache") == name) {
+ subHeap = HEAP_DALVIK_OTHER_CODE_CACHE;
+ } else if (strstr(name, "/dev/ashmem/dalvik-CompilerMetadata") == name) {
+ subHeap = HEAP_DALVIK_OTHER_COMPILER_METADATA;
} else {
- subHeap = HEAP_DALVIK_ACCOUNTING; // Default to accounting.
+ subHeap = HEAP_DALVIK_OTHER_ACCOUNTING; // Default to accounting.
}
} else if (strncmp(name, "/dev/ashmem/CursorWindow", 24) == 0) {
whichHeap = HEAP_CURSOR;
@@ -423,7 +452,8 @@
stats[whichHeap].sharedClean += shared_clean;
stats[whichHeap].swappedOut += swapped_out;
stats[whichHeap].swappedOutPss += swapped_out_pss;
- if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER) {
+ if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER ||
+ whichHeap == HEAP_DEX || whichHeap == HEAP_ART) {
stats[subHeap].pss += pss;
stats[subHeap].swappablePss += swappable_pss;
stats[subHeap].privateDirty += private_dirty;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8ac3642..f5d3a29 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2534,6 +2534,23 @@
<permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
android:protectionLevel="signature" />
+ <!-- Allows applications to get the installed and enabled print services.
+ @hide
+ @SystemApi
+ @TestApi
+ <p>Protection level: signature|preinstalled
+ -->
+ <permission android:name="android.permission.READ_PRINT_SERVICES"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- Allows applications to get the currently recommended print services for printers.
+ @hide
+ @SystemApi
+ <p>Protection level: signature|preinstalled
+ -->
+ <permission android:name="android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS"
+ android:protectionLevel="signature|preinstalled" />
+
<!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
the system can bind to it.
@@ -3139,6 +3156,12 @@
<permission android:name="android.permission.MANAGE_NETWORK_POLICY"
android:protectionLevel="signature" />
+ <!-- @SystemApi Allows an application to manage fallback subscription plans.
+ Note that another app providing plans for an explicit HNI will always
+ take precidence over these fallback plans. @hide -->
+ <permission android:name="android.permission.MANAGE_FALLBACK_SUBSCRIPTION_PLANS"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an application to account its network traffic against other UIDs. Used
by system services like download manager and media server. Not for use by
third party apps. @hide -->
@@ -3843,6 +3866,11 @@
<service android:name="com.android.server.PreloadsFileCacheExpirationJobService"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+
+ <service android:name="com.android.server.camera.CameraStatsJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
</application>
</manifest>
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_00_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_00_mtrl.png
index ddfd5ed..5aa4e98 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_00_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_01_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_01_mtrl.png
index 7ab09d1..2afba7f 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_01_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_02_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_02_mtrl.png
index 8cdf2c3..94c696c 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_02_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_03_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_03_mtrl.png
index e1721fc..2bbc0e0 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_03_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_04_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_04_mtrl.png
index f64d2c7..1554f45 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_04_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_05_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_05_mtrl.png
index c312fd8..f7f9bec 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_05_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_06_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_06_mtrl.png
index 5cb787c..caf35d0 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_06_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_07_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_07_mtrl.png
index 2e759df..428b6cf 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_07_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_08_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_08_mtrl.png
index b4c1b63..5bba9bb 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_08_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_09_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_09_mtrl.png
index 53b435d..d562375 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_09_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_10_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_10_mtrl.png
index 58d81c0..a083bd2 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_10_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_11_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_11_mtrl.png
index 3834afd..cdd80c8f 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_11_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_12_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_12_mtrl.png
index de0f726..f38ba50 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_12_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_13_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_13_mtrl.png
index d8c095d..92d5887 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_13_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_14_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_14_mtrl.png
index e053b97d..e5fb306 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_14_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_15_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_15_mtrl.png
index 7feb4ae..ae62588 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_15_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_16_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_16_mtrl.png
index caed47b..952eda0 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_16_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_17_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_17_mtrl.png
index b38c2ab..d51aa42 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_17_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_18_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_18_mtrl.png
index a1b947f..95a696f 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_18_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_19_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_19_mtrl.png
index b7016fa..a9435e3 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_19_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_20_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_20_mtrl.png
index f4b2253..851168a 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_20_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_21_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_21_mtrl.png
index 1d9943f..c0e15e9 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_21_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_22_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_22_mtrl.png
index 685da61..41a7b9c 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_22_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_23_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_23_mtrl.png
index 8e34fdc..8618f96 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_23_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_24_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_24_mtrl.png
index 3bc67c3..81488d1 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_24_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_25_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_25_mtrl.png
index 78e3c42..6b635c9 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_25_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_26_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_26_mtrl.png
index bfc42fd..8a7e4fc 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_26_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_27_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_27_mtrl.png
index cbe0c18..6f7d3a2 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_27_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_28_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_28_mtrl.png
index 8f68ecb..fc6caf5 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_28_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_29_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_29_mtrl.png
index 324f74f..3554271 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_29_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_30_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_30_mtrl.png
index 9e9435a..6c82a89 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_dark_30_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_dark_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_00_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_00_mtrl.png
index 9558f21..d6daf80 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_00_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_01_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_01_mtrl.png
index 1b1fe4d..41275f1 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_01_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_02_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_02_mtrl.png
index db5fbdc..b63b7c3 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_02_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_03_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_03_mtrl.png
index 39c5f67..403d1b7 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_03_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_04_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_04_mtrl.png
index a166aae..a19aa06 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_04_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_05_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_05_mtrl.png
new file mode 100644
index 0000000..33d4dbf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_06_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_06_mtrl.png
index 243e7aa..ad89fa1 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_06_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_07_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_07_mtrl.png
index a04df8c..9a970c8 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_07_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_08_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_08_mtrl.png
index 97eee99..5c71217 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_08_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_09_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_09_mtrl.png
index 77f13e2..181c812 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_09_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_10_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_10_mtrl.png
index 62346b4..1b285a7 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_10_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_11_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_11_mtrl.png
new file mode 100644
index 0000000..00f1c62
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_12_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_12_mtrl.png
index 7411d24..f86cca7 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_12_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_13_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_13_mtrl.png
index edd8f35..4e47fc8 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_13_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_14_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_14_mtrl.png
index 3f17c95..8b33f2c 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_14_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_15_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_15_mtrl.png
index 6a4521a..451bda7 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_15_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_16_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_16_mtrl.png
index 16f6f9c..dedbff1 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_16_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_17_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_17_mtrl.png
new file mode 100644
index 0000000..d6be31c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_18_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_18_mtrl.png
index 15819d8..bfd1900 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_18_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_19_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_19_mtrl.png
index 433f7c5f..003f13d 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_19_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_20_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_20_mtrl.png
index 8c925bc..5564760 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_20_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_21_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_21_mtrl.png
index b509204..ebc1ae1 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_21_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_22_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_22_mtrl.png
index 30cddc6..92a9230 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_22_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_23_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_23_mtrl.png
new file mode 100644
index 0000000..6f5c84a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_24_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_24_mtrl.png
index 0ff15ea..ba4ab1d 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_24_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_25_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_25_mtrl.png
index 21489b2..f246835 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_25_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_26_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_26_mtrl.png
index 57df6e1..04b790b 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_26_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_27_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_27_mtrl.png
index d8821ad..63e0d79 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_27_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_28_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_28_mtrl.png
index 8222d28..89027f4 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_28_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_29_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_29_mtrl.png
new file mode 100644
index 0000000..4b4870b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connected_light_30_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connected_light_30_mtrl.png
index fe85c1d..1dae891 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connected_light_30_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connected_light_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_00_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_00_mtrl.png
index 1f180ad..5aa4e98 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_00_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_01_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_01_mtrl.png
index b27556a..2afba7f 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_01_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_02_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_02_mtrl.png
index 1235c5d..94c696c 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_02_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_03_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_03_mtrl.png
index cd60ff4..2bbc0e0 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_03_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_04_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_04_mtrl.png
index 96f3272..1554f45 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_04_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_05_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_05_mtrl.png
index 93b78fc..f7f9bec 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_05_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_06_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_06_mtrl.png
index 5ec23a0..caf35d0 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_06_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_07_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_07_mtrl.png
index ed5bed8..4c36c70 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_07_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_08_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_08_mtrl.png
index 1842d3b..5bba9bb 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_08_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_09_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_09_mtrl.png
index 538d420..d562375 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_09_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_10_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_10_mtrl.png
index abd8ed3..19b7700 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_10_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_11_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_11_mtrl.png
index 3d5a173..d86fe79 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_11_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_12_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_12_mtrl.png
index 0ad076f..c38e4be 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_12_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_13_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_13_mtrl.png
index 392aa23..4ea1ce3 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_13_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_14_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_14_mtrl.png
index 6f64e23..b49e12c 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_14_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_15_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_15_mtrl.png
index 92f932c..5ce7064 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_15_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_16_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_16_mtrl.png
index 14a07f0..ebc0b50 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_16_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_17_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_17_mtrl.png
index 4f2ef73..04af459 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_17_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_18_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_18_mtrl.png
index 4b110fa..862f22d 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_18_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_19_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_19_mtrl.png
index 9162814..9d8f434 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_19_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_20_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_20_mtrl.png
index 48631d8..099703e 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_20_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_21_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_21_mtrl.png
index 67720fd..6463743 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_21_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_22_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_22_mtrl.png
index b237c01..c3808eb 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_22_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_23_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_23_mtrl.png
index f265ac9..14215bb 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_23_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_24_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_24_mtrl.png
index 05e8139..0720a34 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_24_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_25_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_25_mtrl.png
index d64eba8..08d94b0 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_25_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_26_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_26_mtrl.png
index cee235f..58bd80b 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_26_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_27_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_27_mtrl.png
index ba6ce2f..0c7a1f3 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_27_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_28_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_28_mtrl.png
index 38b822a..1a8c1e6 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_28_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_29_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_29_mtrl.png
index 4639678..10bc6c4 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_29_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_30_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_30_mtrl.png
index 1f180ad..5aa4e98 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_30_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_dark_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_00_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_00_mtrl.png
index 18d83e9..d6daf80 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_00_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_01_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_01_mtrl.png
index 85b2ca6..41275f1 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_01_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_02_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_02_mtrl.png
index f723872..b63b7c3 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_02_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_03_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_03_mtrl.png
index aa12de2..403d1b7 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_03_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_04_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_04_mtrl.png
index 841bcd9..a19aa06 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_04_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_05_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_05_mtrl.png
index 0d50319..33d4dbf 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_05_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_06_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_06_mtrl.png
index 965a3ad..ad89fa1 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_06_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_07_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_07_mtrl.png
index 9a5a60a..9a970c8 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_07_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_08_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_08_mtrl.png
index 79107fd..5c71217 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_08_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_09_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_09_mtrl.png
index 712b827..181c812 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_09_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_10_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_10_mtrl.png
index 410f684..1b285a7 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_10_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_11_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_11_mtrl.png
index d84e607..4a91688 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_11_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_12_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_12_mtrl.png
index 9f8f46f..4a3bc21 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_12_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_13_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_13_mtrl.png
index c9e01ba..84d944d 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_13_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_14_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_14_mtrl.png
index a9a5f08..8fe61bc 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_14_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_15_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_15_mtrl.png
index 2218d2d..d1a9906 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_15_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_16_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_16_mtrl.png
index db4ead0..3de70e3 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_16_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_17_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_17_mtrl.png
index bbeedbc..a2caa31 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_17_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_18_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_18_mtrl.png
index c3f5036..984e0b1 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_18_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_19_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_19_mtrl.png
index 370e49c..1a20df8 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_19_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_20_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_20_mtrl.png
index f1ca743..2ffe3f7 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_20_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_21_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_21_mtrl.png
index 63c1425..87f7880 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_21_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_22_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_22_mtrl.png
index d0ee3fe..39f1db7 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_22_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_23_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_23_mtrl.png
index 936d5de..e1501fe6 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_23_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_24_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_24_mtrl.png
index 703aba9..1ac9df6 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_24_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_25_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_25_mtrl.png
index 2f0aacb..486225b 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_25_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_26_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_26_mtrl.png
index f975916..e2aec2b 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_26_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_27_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_27_mtrl.png
index a81d8f8..c63ee04 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_27_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_28_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_28_mtrl.png
index 6419d90..2f92d61 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_28_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_29_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_29_mtrl.png
index 801e5f6..9b7c065 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_29_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_30_mtrl.png b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_30_mtrl.png
index 18d83e9..d6daf80 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_connecting_light_30_mtrl.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_connecting_light_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_00_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_00_mtrl.png
index c6e2e53..49d353d 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_00_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_01_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_01_mtrl.png
index c573cd8..ca1bf45 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_01_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_02_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_02_mtrl.png
index a2a31f7..69611bc 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_02_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_03_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_03_mtrl.png
index 9f5561f..53e0f64 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_03_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_04_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_04_mtrl.png
index 2067c44..bcf2a18 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_04_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_05_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_05_mtrl.png
index d32a2fd..937f5a0 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_05_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_06_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_06_mtrl.png
index 6982586..5a5e2d5 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_06_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_07_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_07_mtrl.png
index a868a0c..82cf33c 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_07_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_08_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_08_mtrl.png
index 64fc494..522b331 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_08_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_09_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_09_mtrl.png
index 752155a..23723a3 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_09_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_10_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_10_mtrl.png
index f20c33e..313b6d2 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_10_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_11_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_11_mtrl.png
index 37cb412..cfbc110 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_11_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_12_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_12_mtrl.png
index fe332bf..2b2c628 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_12_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_13_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_13_mtrl.png
index 62c6cd6..260adca 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_13_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_14_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_14_mtrl.png
index bd7ad0c..cadb1c5 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_14_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_15_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_15_mtrl.png
index eb30288..b91e799 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_15_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_16_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_16_mtrl.png
index f6499d7..19edb96 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_16_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_17_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_17_mtrl.png
index e0e04a3..e7b20cc 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_17_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_18_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_18_mtrl.png
index 7b8cb18..7ea341e 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_18_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_19_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_19_mtrl.png
index 8a11c7a..fb8b556 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_19_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_20_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_20_mtrl.png
index 3525a4b..91016aa 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_20_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_21_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_21_mtrl.png
index 91fa1cd..c51481a 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_21_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_22_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_22_mtrl.png
index 5743b6b..80d09e2 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_22_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_23_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_23_mtrl.png
index ca095f7..c4ad65f 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_23_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_24_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_24_mtrl.png
index cfbc6b6..060be80 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_24_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_25_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_25_mtrl.png
index 88563fe..e45e858 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_25_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_26_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_26_mtrl.png
index 93f8826..55c3959 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_26_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_27_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_27_mtrl.png
index c10996c..9c11d99 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_27_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_28_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_28_mtrl.png
index c070849..d3c334b 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_28_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_29_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_29_mtrl.png
index 2dd4589..a3164c9 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_29_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_30_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_30_mtrl.png
index 02dd21b..b550760 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_dark_30_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_dark_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_00_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_00_mtrl.png
index 46fea5b..d5efab4 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_00_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_01_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_01_mtrl.png
index fbca13e..74d39ac 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_01_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_02_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_02_mtrl.png
index 71ae120..3775cef 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_02_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_03_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_03_mtrl.png
index 7067870..d960a39 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_03_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_04_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_04_mtrl.png
index 6484f4b..6101cdf 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_04_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_05_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_05_mtrl.png
new file mode 100644
index 0000000..fca6c96
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_06_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_06_mtrl.png
index 06f6528..b2bdc46 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_06_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_07_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_07_mtrl.png
index 4c6a236..9d8335e 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_07_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_08_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_08_mtrl.png
index 9736752..4593765 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_08_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_09_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_09_mtrl.png
index 7b94408..d740810 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_09_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_10_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_10_mtrl.png
index f588e97..7b8a7fc 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_10_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_11_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_11_mtrl.png
new file mode 100644
index 0000000..e5d3c682
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_12_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_12_mtrl.png
index 375d27e..b264a99 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_12_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_13_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_13_mtrl.png
index 9f52306..0232d72 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_13_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_14_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_14_mtrl.png
index 4f219e4..2aa94bb 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_14_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_15_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_15_mtrl.png
index 6928e4ea..693f6c6 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_15_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_16_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_16_mtrl.png
index 7dab339..b7aea5c 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_16_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_17_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_17_mtrl.png
new file mode 100644
index 0000000..217cb3d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_18_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_18_mtrl.png
index 71f9afa..933f338 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_18_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_19_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_19_mtrl.png
index c8dba8d..a2ced71 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_19_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_20_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_20_mtrl.png
index 5923869..4303ca4 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_20_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_21_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_21_mtrl.png
index 5c2e9d3..c4d9559 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_21_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_22_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_22_mtrl.png
index 74464ba..a6e278b 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_22_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_23_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_23_mtrl.png
new file mode 100644
index 0000000..19bf6c2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_24_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_24_mtrl.png
index 73b6e12..c6c2163 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_24_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_25_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_25_mtrl.png
index e88bf8b..fe87238 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_25_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_26_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_26_mtrl.png
index c551370..229c489 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_26_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_27_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_27_mtrl.png
index 82380e5..64155d9 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_27_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_28_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_28_mtrl.png
index aed77cb..cb4c0ed 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_28_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_29_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_29_mtrl.png
new file mode 100644
index 0000000..a85c70c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connected_light_30_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connected_light_30_mtrl.png
index bf8bedf..d99afbf 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connected_light_30_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connected_light_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_00_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_00_mtrl.png
index 9ef3ea6..49d353d 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_00_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_01_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_01_mtrl.png
index a6bf744..ca1bf45 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_01_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_02_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_02_mtrl.png
index 0bca0a2..69611bc 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_02_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_03_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_03_mtrl.png
index 2850d0b..53e0f64 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_03_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_04_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_04_mtrl.png
index 28045ef..bcf2a18 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_04_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_05_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_05_mtrl.png
index 148c684..937f5a0 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_05_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_06_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_06_mtrl.png
index b3f7cf5..5a5e2d5 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_06_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_07_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_07_mtrl.png
index 1c39764..82cf33c 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_07_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_08_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_08_mtrl.png
index f7bfb79..522b331 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_08_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_09_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_09_mtrl.png
index a689890..23723a3 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_09_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_10_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_10_mtrl.png
index b860164..313b6d2 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_10_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_11_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_11_mtrl.png
index 76ea54c..db37fc5 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_11_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_12_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_12_mtrl.png
index 44a818a..79941dc 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_12_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_13_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_13_mtrl.png
index 40a8654..3361fe2 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_13_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_14_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_14_mtrl.png
index 02c6989..5649d0f 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_14_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_15_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_15_mtrl.png
index 0749100..801b562 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_15_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_16_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_16_mtrl.png
index c820e4a..38e1408 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_16_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_17_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_17_mtrl.png
index 081f548..f99797d 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_17_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_18_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_18_mtrl.png
index bbdc3c8..7048711 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_18_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_19_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_19_mtrl.png
index 1f9653f..6f60804 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_19_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_20_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_20_mtrl.png
index 2f8bdf5..da3a23b 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_20_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_21_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_21_mtrl.png
index 1400616..4007ed1 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_21_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_22_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_22_mtrl.png
index 887e00d..518d2b9 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_22_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_23_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_23_mtrl.png
index 84eab64..d821697 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_23_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_24_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_24_mtrl.png
index 6815686..aa19608 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_24_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_25_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_25_mtrl.png
index 1cab259..81bf08c 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_25_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_26_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_26_mtrl.png
index c5d149a..1bb7aec 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_26_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_27_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_27_mtrl.png
index 22495c5..864795c 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_27_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_28_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_28_mtrl.png
index cc60f35..ed07e9f 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_28_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_29_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_29_mtrl.png
index cff5567..a188260 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_29_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_30_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_30_mtrl.png
index 9ef3ea6..49d353d 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_30_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_dark_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_00_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_00_mtrl.png
index cbcc75a..d5efab4 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_00_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_01_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_01_mtrl.png
index 52a5ee8..74d39ac 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_01_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_02_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_02_mtrl.png
index 528554a..3775cef 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_02_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_03_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_03_mtrl.png
index 28b0f41..d960a39 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_03_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_04_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_04_mtrl.png
index 772d39e..6101cdf 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_04_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_05_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_05_mtrl.png
index c87eecf..fca6c96 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_05_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_06_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_06_mtrl.png
index d980254..b2bdc46 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_06_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_07_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_07_mtrl.png
index d38af8e..9d8335e 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_07_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_08_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_08_mtrl.png
index 92087b7..4593765 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_08_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_09_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_09_mtrl.png
index 5b161a2..d740810 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_09_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_10_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_10_mtrl.png
index 62a925f..7b8a7fc 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_10_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_11_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_11_mtrl.png
index 6b8ac60..aadb0cd 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_11_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_12_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_12_mtrl.png
index cfcdfac..628e63d 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_12_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_13_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_13_mtrl.png
index e124d27..dfc63ae 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_13_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_14_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_14_mtrl.png
index 98cb933..450ead1 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_14_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_15_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_15_mtrl.png
index d2867c1..6424958 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_15_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_16_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_16_mtrl.png
index df22da9..c5b7fa4 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_16_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_17_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_17_mtrl.png
index 376ebf6..13fcf6f 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_17_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_18_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_18_mtrl.png
index 3178adb..5be9c69 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_18_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_19_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_19_mtrl.png
index fc9a8e2..3de2194 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_19_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_20_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_20_mtrl.png
index 4176852..c40a2cf 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_20_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_21_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_21_mtrl.png
index c598e69..9923ccd 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_21_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_22_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_22_mtrl.png
index e186799..8a000c1 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_22_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_23_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_23_mtrl.png
index 532bfba..3680ced 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_23_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_24_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_24_mtrl.png
index b47cf1f..d014f5e 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_24_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_25_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_25_mtrl.png
index 95fed6cac..a8aefdb 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_25_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_26_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_26_mtrl.png
index 9097ffa..4716d66 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_26_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_27_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_27_mtrl.png
index cfd8d06..fdeaf4f 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_27_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_28_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_28_mtrl.png
index 2013328..9accc7a 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_28_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_29_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_29_mtrl.png
index 39d8e5b..1f0a327 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_29_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_30_mtrl.png b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_30_mtrl.png
index cbcc75a..d5efab4 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_connecting_light_30_mtrl.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_connecting_light_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_00_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_00_mtrl.png
index 4c54483..0907a1e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_00_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_01_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_01_mtrl.png
index ea059cf..365d96e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_01_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_02_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_02_mtrl.png
index 3f4d554..7191add 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_02_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_03_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_03_mtrl.png
index e6dbf9b7..fd8a5df 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_03_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_04_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_04_mtrl.png
index 6e173dd..9ae573b 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_04_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_05_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_05_mtrl.png
index 8ae261f..a41d549 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_05_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_06_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_06_mtrl.png
index 07040a2..4faef98 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_06_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_07_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_07_mtrl.png
index 2a35082..337372c 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_07_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_08_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_08_mtrl.png
index dc790f3..a78de95 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_08_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_09_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_09_mtrl.png
index 47c7f7e..74f8912 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_09_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_10_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_10_mtrl.png
index 0f21484..0b868fb 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_10_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_11_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_11_mtrl.png
index 89e811c..8c381cc 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_11_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_12_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_12_mtrl.png
index 7da883a..17e40a0 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_12_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_13_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_13_mtrl.png
index 928fd30..5280b2f 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_13_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_14_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_14_mtrl.png
index d9718df..dfe29ce 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_14_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_15_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_15_mtrl.png
index 85289cc..663d361 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_15_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_16_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_16_mtrl.png
index a36ba09..5e2ecdf 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_16_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_17_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_17_mtrl.png
index 234d92f..8d6c1f24 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_17_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_18_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_18_mtrl.png
index 156a727..4edd1ac 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_18_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_19_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_19_mtrl.png
index 4e9e5ed..af45ea7 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_19_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_20_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_20_mtrl.png
index 0416289..f075756 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_20_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_21_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_21_mtrl.png
index 01c1798..69bd877 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_21_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_22_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_22_mtrl.png
index 9dfb7b3..8c956bb 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_22_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_23_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_23_mtrl.png
index af37804..76bf9ab 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_23_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_24_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_24_mtrl.png
index 08a5e41..1a7f9a1 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_24_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_25_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_25_mtrl.png
index 428e20c..1275eaa 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_25_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_26_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_26_mtrl.png
index c57b40c..c4ed71d 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_26_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_27_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_27_mtrl.png
index 5c06f46..03252d7 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_27_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_28_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_28_mtrl.png
index 3eac7d4..ea8ee85 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_28_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_29_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_29_mtrl.png
index ac970b00b..b024c4e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_29_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_30_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_30_mtrl.png
index df1e54c..35516f6 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_30_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_dark_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_00_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_00_mtrl.png
index 495606c..dbd9854 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_00_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_01_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_01_mtrl.png
index b4604c5..f0c30b1 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_01_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_02_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_02_mtrl.png
index 72c1f6e..f21743b 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_02_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_03_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_03_mtrl.png
index 117c5b5..0b96ae0 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_03_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_04_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_04_mtrl.png
index e8cbbb8..2e5407f 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_04_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_05_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_05_mtrl.png
new file mode 100644
index 0000000..0beb389
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_06_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_06_mtrl.png
index 35341d7..a41586e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_06_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_07_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_07_mtrl.png
index 8f17e37..709f650 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_07_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_08_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_08_mtrl.png
index 93a977f..494a716 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_08_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_09_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_09_mtrl.png
index 2ebed2a..9ec48f4 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_09_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_10_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_10_mtrl.png
index dfa0643..f4c22b1 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_10_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_11_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_11_mtrl.png
new file mode 100644
index 0000000..6fd600f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_12_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_12_mtrl.png
index dd2d79a..cfee3e1 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_12_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_13_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_13_mtrl.png
index e9064d5..cc79904 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_13_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_14_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_14_mtrl.png
index 50cf467..28c7441 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_14_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_15_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_15_mtrl.png
index 7be4fba..6c7e534 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_15_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_16_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_16_mtrl.png
index ba82804..e7d20d7 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_16_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_17_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_17_mtrl.png
new file mode 100644
index 0000000..ea492d2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_18_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_18_mtrl.png
index 220cbcc..92c6ad8 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_18_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_19_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_19_mtrl.png
index bbb16ba..f666d89 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_19_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_20_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_20_mtrl.png
index 8f6c739..c2b600d 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_20_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_21_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_21_mtrl.png
index 9ab0656..31736aa 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_21_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_22_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_22_mtrl.png
index 9bea94e..3032ef0 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_22_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_23_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_23_mtrl.png
new file mode 100644
index 0000000..1d5cbc0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_24_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_24_mtrl.png
index baa05f7..84ebcc3 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_24_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_25_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_25_mtrl.png
index 35d8280..505aadf 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_25_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_26_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_26_mtrl.png
index 76900ee..3b8c662 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_26_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_27_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_27_mtrl.png
index 9f86a59..d650c07 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_27_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_28_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_28_mtrl.png
index f9a6d4c..3caa40d 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_28_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_29_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_29_mtrl.png
new file mode 100644
index 0000000..d3f8ea6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_30_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_30_mtrl.png
index 235e12d..b54396c 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connected_light_30_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connected_light_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_00_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_00_mtrl.png
index 1d85b66..0907a1e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_00_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_01_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_01_mtrl.png
index 856292f..365d96e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_01_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_02_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_02_mtrl.png
index 68223c3..7191add 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_02_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_03_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_03_mtrl.png
index db58987..fd8a5df 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_03_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_04_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_04_mtrl.png
index 668789a..9ae573b 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_04_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_05_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_05_mtrl.png
index 268879e..a41d549 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_05_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_06_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_06_mtrl.png
index 72096a7..4faef98 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_06_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_07_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_07_mtrl.png
index 04cce3d..337372c 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_07_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_08_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_08_mtrl.png
index 573e6d6..a78de95 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_08_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_09_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_09_mtrl.png
index 64556a4..74f8912 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_09_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_10_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_10_mtrl.png
index 4a0d428..0b868fb 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_10_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_11_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_11_mtrl.png
index c3ab54b..90ca46c 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_11_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_12_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_12_mtrl.png
index b431a09..db02019 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_12_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_13_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_13_mtrl.png
index 6a0f0af..ce5ee81 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_13_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_14_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_14_mtrl.png
index 1c69324..3dcbef6 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_14_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_15_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_15_mtrl.png
index 7d90e57..7646f18 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_15_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_16_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_16_mtrl.png
index 59a4121..c16cac9 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_16_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_17_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_17_mtrl.png
index 2baf7f6..7dbc57c 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_17_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_18_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_18_mtrl.png
index 66c61d4..39d17e0 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_18_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_19_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_19_mtrl.png
index 8a77aa5..ad0e121 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_19_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_20_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_20_mtrl.png
index 6820b62..30ea5df 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_20_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_21_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_21_mtrl.png
index ce4a1c7..151a222 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_21_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_22_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_22_mtrl.png
index fe765c4..7d4e660 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_22_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_23_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_23_mtrl.png
index 85897ef..8e26d54 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_23_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_24_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_24_mtrl.png
index 7a68cf7..e85f239 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_24_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_25_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_25_mtrl.png
index bf0a053..81f38ac 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_25_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_26_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_26_mtrl.png
index 5bb46b3..5a50e6a 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_26_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_27_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_27_mtrl.png
index cc9cf53..6069dad 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_27_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_28_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_28_mtrl.png
index c98d4e5..37cc4c6 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_28_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_29_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_29_mtrl.png
index 43bb757..aff0d4c 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_29_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_30_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_30_mtrl.png
index 1d85b66..0907a1e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_30_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_dark_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_00_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_00_mtrl.png
index 231aec4..dbd9854 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_00_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_01_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_01_mtrl.png
index e20c2a2..f0c30b1 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_01_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_02_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_02_mtrl.png
index 9c247a6..f21743b 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_02_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_03_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_03_mtrl.png
index 2a5da5f..0b96ae0 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_03_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_04_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_04_mtrl.png
index 31224e1..2e5407f 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_04_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_05_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_05_mtrl.png
index 1a792fb..302fafa 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_05_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_06_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_06_mtrl.png
index 9c9190d..a41586e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_06_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_07_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_07_mtrl.png
index 07b666c..709f650 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_07_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_08_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_08_mtrl.png
index 8cc43fd..494a716 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_08_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_09_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_09_mtrl.png
index 7f8a801..9ec48f4 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_09_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_10_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_10_mtrl.png
index fe321ac..f4c22b1 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_10_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_11_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_11_mtrl.png
index a37741c..7d72685 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_11_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_12_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_12_mtrl.png
index 395bebd..4c545ef 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_12_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_13_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_13_mtrl.png
index 746580d..a8e9b00 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_13_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_14_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_14_mtrl.png
index b279cf2..b67140d 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_14_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_15_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_15_mtrl.png
index d99a66e..166bdae 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_15_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_16_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_16_mtrl.png
index e0232dc..1bda465 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_16_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_17_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_17_mtrl.png
index de27b75..cc8ec51 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_17_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_18_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_18_mtrl.png
index e2e2c47..cf2013c 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_18_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_19_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_19_mtrl.png
index 53cc9a6..daa1ca1 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_19_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_20_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_20_mtrl.png
index 1b2422c..56355d9 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_20_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_21_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_21_mtrl.png
index 8d03f55..42657ec 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_21_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_22_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_22_mtrl.png
index e938e3a..53e4121 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_22_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_23_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_23_mtrl.png
index d3c0395..f6e9ffa 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_23_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_24_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_24_mtrl.png
index f8b5ab3..a313e16 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_24_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_25_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_25_mtrl.png
index aa935f8..40034b6 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_25_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_26_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_26_mtrl.png
index 7a53689..678f972 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_26_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_27_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_27_mtrl.png
index 31cee64..d2a3707 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_27_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_28_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_28_mtrl.png
index 98db967..427c52e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_28_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_29_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_29_mtrl.png
index 5b05e0f..8a4d807 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_29_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_30_mtrl.png b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_30_mtrl.png
index 231aec4..dbd9854 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_30_mtrl.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_connecting_light_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_00_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_00_mtrl.png
index 80ffc08..97949c6 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_00_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_01_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_01_mtrl.png
index 5640697..3f35bcd 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_01_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_02_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_02_mtrl.png
index c1ec38a..0ed2094 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_02_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_03_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_03_mtrl.png
index 781f469..7fa7f01 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_03_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_04_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_04_mtrl.png
index 9edcb9f..b7e1ea1 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_04_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_05_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_05_mtrl.png
index fe9eee4..ff07932 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_05_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_06_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_06_mtrl.png
index e5155fe..4a7b283 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_06_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_07_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_07_mtrl.png
index e1bf3b8..41c4443 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_07_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_08_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_08_mtrl.png
index 4ec553a..461fa46 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_08_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_09_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_09_mtrl.png
index 67685b4..f96d1f0 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_09_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_10_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_10_mtrl.png
index 527dbde..87a9b49 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_10_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_11_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_11_mtrl.png
index 77f9e46..96b5366 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_11_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_12_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_12_mtrl.png
index a0395a1..532a86d 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_12_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_13_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_13_mtrl.png
index 26e7307..9f37eb2 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_13_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_14_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_14_mtrl.png
index 632457f..2437e0e 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_14_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_15_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_15_mtrl.png
index d80234a..79bc6ce 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_15_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_16_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_16_mtrl.png
index 4297fef..9dbbe2f 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_16_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_17_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_17_mtrl.png
index a646b4a..1da48b8 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_17_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_18_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_18_mtrl.png
index fc49b39..8963582 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_18_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_19_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_19_mtrl.png
index bfa795e..ec4be83 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_19_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_20_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_20_mtrl.png
index 70f49a9..4658fc3 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_20_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_21_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_21_mtrl.png
index 7d1d7c7..3ecd6bd 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_21_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_22_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_22_mtrl.png
index 94692f0..565e8de 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_22_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_23_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_23_mtrl.png
index f38d3fb..9c5c607 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_23_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_24_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_24_mtrl.png
index 3bc7ab9..87b84a7 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_24_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_25_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_25_mtrl.png
index b644a77..9e12e5b 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_25_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_26_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_26_mtrl.png
index 47882834..85e8791 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_26_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_27_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_27_mtrl.png
index dedfebc..a7bd75d 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_27_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_28_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_28_mtrl.png
index be40ac1..204f393 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_28_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_29_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_29_mtrl.png
index d4376f5..78f787a 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_29_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_30_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_30_mtrl.png
index aca83da..a2e61c2 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_30_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_dark_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_00_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_00_mtrl.png
index c3f20e5..80d5155 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_00_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_01_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_01_mtrl.png
index 49d5421..8ec05ae 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_01_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_02_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_02_mtrl.png
index 33c3956..42cd13c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_02_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_03_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_03_mtrl.png
index aa349f6..f43727f 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_03_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_04_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_04_mtrl.png
index af6117a..e61a05c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_04_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_05_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_05_mtrl.png
new file mode 100644
index 0000000..8dc5976
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_06_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_06_mtrl.png
index e7e8d2a..ead968e 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_06_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_07_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_07_mtrl.png
index 5470a04..52aa7d5 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_07_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_08_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_08_mtrl.png
index d73361a..58986d4 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_08_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_09_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_09_mtrl.png
index eba4134..42d6c7c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_09_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_10_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_10_mtrl.png
index c27f694..e7e0e60 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_10_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_11_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_11_mtrl.png
new file mode 100644
index 0000000..75bd261
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_12_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_12_mtrl.png
index c60098e..5207dac 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_12_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_13_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_13_mtrl.png
index 3026145..c2f69e7 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_13_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_14_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_14_mtrl.png
index 377e026..167f882 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_14_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_15_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_15_mtrl.png
index f697916..d6a85f2 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_15_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_16_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_16_mtrl.png
index f5df91c..cb0390d 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_16_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_17_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_17_mtrl.png
new file mode 100644
index 0000000..6a65d15
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_18_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_18_mtrl.png
index d2b5e76..8086a55 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_18_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_19_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_19_mtrl.png
index 213f37e..eee4115 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_19_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_20_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_20_mtrl.png
index 23ba68e..d214ad1 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_20_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_21_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_21_mtrl.png
index 5826760..ac56ac4 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_21_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_22_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_22_mtrl.png
index 1f66a8e..49af14e 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_22_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_23_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_23_mtrl.png
new file mode 100644
index 0000000..5003095b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_24_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_24_mtrl.png
index af64c3c..62054a0 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_24_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_25_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_25_mtrl.png
index 8284f70..4c83dd4 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_25_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_26_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_26_mtrl.png
index 18c513e..a55f8e4 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_26_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_27_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_27_mtrl.png
index d6d6b17..81567b7 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_27_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_28_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_28_mtrl.png
index 89b9d3a..4047475 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_28_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_29_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_29_mtrl.png
new file mode 100644
index 0000000..23db45a
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_30_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_30_mtrl.png
index 1ae65d0..e7d9961 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_30_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connected_light_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_00_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_00_mtrl.png
index 9acbd29..97949c6 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_00_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_01_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_01_mtrl.png
index 5de2581..3f35bcd 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_01_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_02_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_02_mtrl.png
index 9a566b8..0ed2094 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_02_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_03_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_03_mtrl.png
index bceaead..7fa7f01 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_03_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_04_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_04_mtrl.png
index faa78ec..b7e1ea1 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_04_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_05_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_05_mtrl.png
index 78f8434..ff07932 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_05_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_06_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_06_mtrl.png
index 7746465..4a7b283 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_06_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_07_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_07_mtrl.png
index 1df1530..41c4443 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_07_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_08_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_08_mtrl.png
index ae9702a..461fa46 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_08_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_09_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_09_mtrl.png
index f637e79..f96d1f0 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_09_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_10_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_10_mtrl.png
index fa8f062..87a9b49 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_10_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_11_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_11_mtrl.png
index a780ae4..685a340 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_11_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_12_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_12_mtrl.png
index cb2a15a..b49c30e 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_12_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_13_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_13_mtrl.png
index 7588633..aa92d9e 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_13_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_14_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_14_mtrl.png
index bbcedcc..73d487c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_14_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_15_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_15_mtrl.png
index c521567..f427d0c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_15_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_16_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_16_mtrl.png
index 6add7d3..8fbaa08 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_16_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_17_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_17_mtrl.png
index e907da5..1f0fcd6 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_17_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_18_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_18_mtrl.png
index 733af5f..80c905a 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_18_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_19_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_19_mtrl.png
index cf990db..9b27fa3 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_19_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_20_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_20_mtrl.png
index c025fff..24f2b75 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_20_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_21_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_21_mtrl.png
index 443fcd8..f499d0a 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_21_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_22_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_22_mtrl.png
index 5532128..e22ca9b 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_22_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_23_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_23_mtrl.png
index 2800b00..596ca8b 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_23_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_24_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_24_mtrl.png
index 31fd5de..363a4d6 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_24_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_25_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_25_mtrl.png
index 8a7c4f9..10e275b 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_25_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_26_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_26_mtrl.png
index f4258ccd..aa87c9e 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_26_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_27_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_27_mtrl.png
index 5d87f0c..77a2b8f 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_27_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_28_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_28_mtrl.png
index 366537e..f6108d9 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_28_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_29_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_29_mtrl.png
index 6326ac5..e3a6a20 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_29_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_30_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_30_mtrl.png
index 9acbd29..fa6dc9a 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_30_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_dark_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_00_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_00_mtrl.png
index 5d4273d..80d5155 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_00_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_01_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_01_mtrl.png
index 4524cb1..8ec05ae 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_01_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_02_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_02_mtrl.png
index 766caef..42cd13c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_02_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_03_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_03_mtrl.png
index c25cc84..f43727f 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_03_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_04_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_04_mtrl.png
index 8b02b5a..849638b 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_04_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_05_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_05_mtrl.png
index efc4d55..06e21b0 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_05_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_06_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_06_mtrl.png
index a504cb5..ead968e 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_06_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_07_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_07_mtrl.png
index 093531c..52aa7d5 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_07_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_08_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_08_mtrl.png
index f847e1b..58986d4 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_08_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_09_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_09_mtrl.png
index 35d97ef..42d6c7c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_09_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_10_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_10_mtrl.png
index 140b74b..e7e0e60 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_10_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_11_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_11_mtrl.png
index da14c62..933be30 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_11_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_12_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_12_mtrl.png
index f7ae5e7..b39230f 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_12_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_13_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_13_mtrl.png
index 2251e14..01492c4 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_13_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_14_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_14_mtrl.png
index 131c64d..b56aa16 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_14_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_15_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_15_mtrl.png
index 92ac75a..bdd3d2c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_15_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_16_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_16_mtrl.png
index 2d8ebc4..b76d5d7 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_16_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_17_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_17_mtrl.png
index 1b804bb..5fb12e7 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_17_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_18_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_18_mtrl.png
index 5457baa..64fe3c5 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_18_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_19_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_19_mtrl.png
index 47d5bd4..68fd051 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_19_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_20_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_20_mtrl.png
index acadb30..a4fd4cc 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_20_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_21_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_21_mtrl.png
index f17cb4af..40b02f0 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_21_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_22_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_22_mtrl.png
index 3766cb9..fcd6ddb 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_22_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_23_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_23_mtrl.png
index 307e313..cb250dd 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_23_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_24_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_24_mtrl.png
index 850e96a..43d2119 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_24_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_25_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_25_mtrl.png
index ec31278..bdcaf69 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_25_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_26_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_26_mtrl.png
index 56b1c0f..3d2bff4 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_26_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_27_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_27_mtrl.png
index 47cf578..290e7d9 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_27_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_28_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_28_mtrl.png
index a9ffc25..6c670fb 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_28_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_29_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_29_mtrl.png
index 96e4502..e93c824 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_29_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_30_mtrl.png b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_30_mtrl.png
index 5d4273d..80d5155 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_30_mtrl.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_connecting_light_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_00_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_00_mtrl.png
index 81af491..5561c62 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_00_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_01_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_01_mtrl.png
index 2a00390..9eff17e 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_01_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_02_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_02_mtrl.png
index 87b5f5a..67923e2 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_02_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_03_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_03_mtrl.png
index 0a0d97f..1aa0e98 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_03_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_04_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_04_mtrl.png
index c4f0a38..7cd549d 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_04_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_05_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_05_mtrl.png
index e084de3..2c14d79 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_05_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_06_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_06_mtrl.png
index 899c37d..9f061a5 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_06_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_07_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_07_mtrl.png
index 7ff2f313..fe15230 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_07_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_08_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_08_mtrl.png
index 737ff62..220a4fe 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_08_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_09_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_09_mtrl.png
index 5125e4f..77aac4c 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_09_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_10_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_10_mtrl.png
index 3a7d3b7..bf69188 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_10_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_11_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_11_mtrl.png
index 6d05101..22197da 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_11_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_12_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_12_mtrl.png
index 99f93cf..380e929 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_12_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_13_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_13_mtrl.png
index a4a258e..d93a600 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_13_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_14_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_14_mtrl.png
index 35e58d5..3709d5f 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_14_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_15_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_15_mtrl.png
index 4b012b6..2a5019b 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_15_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_16_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_16_mtrl.png
index eaa8cf4..f75a072 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_16_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_17_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_17_mtrl.png
index 389637ef..c8dcd0d 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_17_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_18_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_18_mtrl.png
index 4e3484e..172775e 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_18_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_19_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_19_mtrl.png
index 12c6b83..2f081fd 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_19_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_20_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_20_mtrl.png
index a3eb0f1..cb4c55b 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_20_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_21_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_21_mtrl.png
index 8a98d5f..de155f6 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_21_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_22_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_22_mtrl.png
index 6896038..2cc028d 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_22_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_23_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_23_mtrl.png
index 2a0e403..e848d08 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_23_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_24_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_24_mtrl.png
index 5043219..584c2f8 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_24_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_25_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_25_mtrl.png
index 58b5eef..c9299be 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_25_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_26_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_26_mtrl.png
index 553209c..8abcbd6 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_26_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_27_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_27_mtrl.png
index 48a38b5..ee53e47 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_27_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_28_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_28_mtrl.png
index ead8201..b10d23a 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_28_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_29_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_29_mtrl.png
index cb6a80b..65a2363 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_29_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_30_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_30_mtrl.png
index b7bcbb9..2b73472 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_30_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_dark_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_00_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_00_mtrl.png
index 8397f98..6a656b8 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_00_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_01_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_01_mtrl.png
index eb5e3cf..7d3a3b6 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_01_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_02_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_02_mtrl.png
index 8aaa830..6b22554 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_02_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_03_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_03_mtrl.png
index 668df66..0a9245c 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_03_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_04_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_04_mtrl.png
index abbe1ce..f9a7f6c 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_04_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_05_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_05_mtrl.png
index 85a1d17..ac396ed 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_05_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_06_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_06_mtrl.png
index e2beede..8c15241d 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_06_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_07_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_07_mtrl.png
index 726bf50..e6a75e2 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_07_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_08_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_08_mtrl.png
index cdf7621..90280a9 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_08_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_09_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_09_mtrl.png
index f69cfd5..d9a4632 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_09_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_10_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_10_mtrl.png
index 51ba70e..b1ae68b 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_10_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_11_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_11_mtrl.png
index 69e0b67..e5cba8f 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_11_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_12_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_12_mtrl.png
index 8b12a77..611faeb 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_12_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_13_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_13_mtrl.png
index 95c5074..dfada4d 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_13_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_14_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_14_mtrl.png
index 26ee160..6118202 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_14_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_15_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_15_mtrl.png
index a651506..60d5199 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_15_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_16_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_16_mtrl.png
index 58978c6..ee0b672 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_16_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_17_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_17_mtrl.png
index f5cf8f7..5a97f67 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_17_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_18_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_18_mtrl.png
index b35afdd..9237a7d 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_18_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_19_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_19_mtrl.png
index 222abf4..4d4c663 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_19_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_20_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_20_mtrl.png
index c71b11f..141f9f6 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_20_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_21_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_21_mtrl.png
index b96abd9..2baa531 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_21_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_22_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_22_mtrl.png
index 6aedd05..7a911d5 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_22_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_23_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_23_mtrl.png
index 84e5f94..a760b85 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_23_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_24_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_24_mtrl.png
index 95d38b4..5c15a87 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_24_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_25_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_25_mtrl.png
index 4690016..36a9f1f 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_25_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_26_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_26_mtrl.png
index 60f9f48..03e8c9f 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_26_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_27_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_27_mtrl.png
index 32bcf27..533c694 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_27_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_28_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_28_mtrl.png
index 11e51f3..ead60f5 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_28_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_29_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_29_mtrl.png
index 43f51fe..0a8534f 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_29_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_30_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_30_mtrl.png
index 8d6d3ddd..fa69ad0 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_30_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connected_light_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_00_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_00_mtrl.png
index 81af491..5561c62 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_00_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_01_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_01_mtrl.png
index 2a00390..9eff17e 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_01_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_02_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_02_mtrl.png
index 87b5f5a..67923e2 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_02_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_03_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_03_mtrl.png
index 0a0d97f..1aa0e98 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_03_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_04_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_04_mtrl.png
index c4f0a38..7cd549d 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_04_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_05_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_05_mtrl.png
index e084de3..2c14d79 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_05_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_06_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_06_mtrl.png
index 899c37d..9f061a5 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_06_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_07_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_07_mtrl.png
index 7ff2f313..fe15230 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_07_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_08_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_08_mtrl.png
index 737ff62..220a4fe 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_08_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_09_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_09_mtrl.png
index 5125e4f..77aac4c 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_09_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_10_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_10_mtrl.png
index 3a7d3b7..bf69188 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_10_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_11_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_11_mtrl.png
index 6369e1f..98b0448 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_11_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_12_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_12_mtrl.png
index 759be25..a926419 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_12_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_13_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_13_mtrl.png
index 51e4386..53f6e3e 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_13_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_14_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_14_mtrl.png
index d52b63f..4a2d1b1 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_14_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_15_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_15_mtrl.png
index 8e41ba9..22cce05 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_15_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_16_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_16_mtrl.png
index c7c63dc..d40db21 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_16_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_17_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_17_mtrl.png
index 18cefd6..0a95b7e 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_17_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_18_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_18_mtrl.png
index 48bb6c9..08698bd 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_18_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_19_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_19_mtrl.png
index 11a09139..698d23a 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_19_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_20_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_20_mtrl.png
index c1e6b51..36ed854 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_20_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_21_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_21_mtrl.png
index afd3b9d..2c0d925 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_21_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_22_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_22_mtrl.png
index 97e0dab..747b901 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_22_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_23_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_23_mtrl.png
index 483046b..bae8665 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_23_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_24_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_24_mtrl.png
index 3c492d9..fd7b1a8 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_24_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_25_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_25_mtrl.png
index 4eecaac..03f624e 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_25_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_26_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_26_mtrl.png
index ce234e6..d2a06ed 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_26_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_27_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_27_mtrl.png
index 95f25c3..c5b2a16 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_27_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_28_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_28_mtrl.png
index 9f880db..8b045cb 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_28_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_29_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_29_mtrl.png
index 3a7551e..522ec67 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_29_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_30_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_30_mtrl.png
index 81af491..5561c62 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_30_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_dark_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_00_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_00_mtrl.png
index 8397f98..6a656b8 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_00_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_00_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_01_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_01_mtrl.png
index eb5e3cf..7d3a3b6 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_01_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_01_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_02_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_02_mtrl.png
index 8aaa830..6b22554 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_02_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_02_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_03_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_03_mtrl.png
index 668df66..0a9245c 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_03_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_03_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_04_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_04_mtrl.png
index abbe1ce..f9a7f6c 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_04_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_04_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_05_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_05_mtrl.png
index 85a1d17..ac396ed 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_05_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_05_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_06_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_06_mtrl.png
index e2beede..8c15241d 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_06_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_06_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_07_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_07_mtrl.png
index 726bf50..e6a75e2 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_07_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_07_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_08_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_08_mtrl.png
index cdf7621..90280a9 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_08_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_08_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_09_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_09_mtrl.png
index f69cfd5..d9a4632 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_09_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_09_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_10_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_10_mtrl.png
index 51ba70e..b1ae68b 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_10_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_10_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_11_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_11_mtrl.png
index 9c81742..e3ce3fd 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_11_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_11_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_12_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_12_mtrl.png
index 939cd54..42482a4 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_12_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_12_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_13_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_13_mtrl.png
index 03615c3..ff30f98 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_13_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_13_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_14_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_14_mtrl.png
index d9d9374..0ddcb55 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_14_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_14_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_15_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_15_mtrl.png
index e81e8c2..46ec435 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_15_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_15_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_16_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_16_mtrl.png
index bfb261a..d95fd77 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_16_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_16_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_17_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_17_mtrl.png
index 03171d0..f116a1f 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_17_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_17_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_18_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_18_mtrl.png
index d0d97db..957db7f 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_18_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_18_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_19_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_19_mtrl.png
index 3c3e9dd..624ec47 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_19_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_19_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_20_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_20_mtrl.png
index 4bd347a..362fba4 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_20_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_20_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_21_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_21_mtrl.png
index 28f3277..24032b9 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_21_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_21_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_22_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_22_mtrl.png
index 30beb55..6e4c83c 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_22_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_22_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_23_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_23_mtrl.png
index df5f1ce..1d2a09e 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_23_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_23_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_24_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_24_mtrl.png
index 6985c8c..7b05dfa 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_24_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_24_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_25_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_25_mtrl.png
index 3370898..30de74a1 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_25_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_25_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_26_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_26_mtrl.png
index 6ef6a2c..b08b782 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_26_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_26_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_27_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_27_mtrl.png
index 60e5ef9..e52a1aa 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_27_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_27_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_28_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_28_mtrl.png
index 76a675c..2c311f5 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_28_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_28_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_29_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_29_mtrl.png
index c92dcd4..efdf5fc 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_29_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_29_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_30_mtrl.png b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_30_mtrl.png
index 8397f98..6a656b8 100644
--- a/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_30_mtrl.png
+++ b/core/res/res/drawable-xxxhdpi/ic_media_route_connecting_light_30_mtrl.png
Binary files differ
diff --git a/core/res/res/drawable/scrollbar_handle_material.xml b/core/res/res/drawable/scrollbar_handle_material.xml
index 33efbba..f020112 100644
--- a/core/res/res/drawable/scrollbar_handle_material.xml
+++ b/core/res/res/drawable/scrollbar_handle_material.xml
@@ -19,7 +19,4 @@
android:shape="rectangle">
<solid
android:color="#84ffffff" />
- <size
- android:width="4dp"
- android:height="4dp" />
</shape>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 186cbbf..1c1ec25 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1509,7 +1509,7 @@
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Koristi prečicu"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
- <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izaberite funkciju koja će se koristiti kada dodirnete dugme Pristupačnost:"</string>
+ <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite funkciju koja će se koristiti kada dodirnete dugme Pristupačnost:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Da promijenite funkcije, dodirnite i držite dugme Pristupačnost."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Uvećanje"</string>
<string name="user_switched" msgid="3768006783166984410">"Trenutni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
@@ -1736,7 +1736,7 @@
<string name="user_creation_adding" msgid="4482658054622099197">"Da li dozvoljavate da <xliff:g id="APP">%1$s</xliff:g> kreira novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g> (Korisnik sa ovim nalogom već postoji)?"</string>
<string name="language_selection_title" msgid="2680677278159281088">"Dodaj jezik"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Izbor regije"</string>
- <string name="search_language_hint" msgid="7042102592055108574">"Ukucajte ime jezika"</string>
+ <string name="search_language_hint" msgid="7042102592055108574">"Upišite ime jezika"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
<string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
<string name="region_picker_section_all" msgid="8966316787153001779">"Sve regije"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index e8df21f..6c5e7e5 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1296,7 +1296,7 @@
<string name="submit" msgid="1602335572089911941">"Enviar"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Se ha habilitado el modo coche"</string>
<string name="car_mode_disable_notification_message" msgid="6301524980144350051">"Toca para salir del modo coche."</string>
- <string name="tethered_notification_title" msgid="3146694234398202601">"Compartir Internet/Zona Wi-Fi activado"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Compartir conexión/Zona Wi-Fi activada"</string>
<string name="tethered_notification_message" msgid="2113628520792055377">"Toca para configurar."</string>
<string name="back_button_label" msgid="2300470004503343439">"Atrás"</string>
<string name="next_button_label" msgid="1080555104677992408">"Siguiente"</string>
@@ -1383,7 +1383,7 @@
<string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Límite de datos móviles superado"</string>
<string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Límite de datos Wi-Fi superado"</string>
<string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Límite superado en <xliff:g id="SIZE">%s</xliff:g>"</string>
- <string name="data_usage_restricted_title" msgid="5965157361036321914">"Conexiones automáticas restringidas"</string>
+ <string name="data_usage_restricted_title" msgid="5965157361036321914">"Datos en segundo plano restringidos"</string>
<string name="data_usage_restricted_body" msgid="469866376337242726">"Toca para quitar la restricción."</string>
<string name="ssl_certificate" msgid="6510040486049237639">"Certificado de seguridad"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Este certificado es válido."</string>
@@ -1618,7 +1618,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"Instalado por el administrador"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"Actualizado por el administrador"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"Eliminado por el administrador"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"Para mejorar la duración de la batería, la función de ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de la transmisión de datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de batería se desactiva automáticamente cuando el dispositivo se está cargando."</string>
+ <string name="battery_saver_description" msgid="1960431123816253034">"Para mejorar la duración de la batería, la función de ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de los datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de batería se desactiva automáticamente cuando el dispositivo se está cargando."</string>
<string name="data_saver_description" msgid="6015391409098303235">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se muestren hasta que no las toques."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 36922d9..b5234a8 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1770,8 +1770,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Ebakuatu kostaldeak eta ibaialdeak berehala eta joan toki seguru batera, adibidez, toki garai batera."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Ez larritu eta bilatu babesleku bat inguruan."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Larrialdi-mezuen proba"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Erantzun"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Ez da onartzen SIM txartela"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Ez dago SIM txartelik"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index a39bc3f..c688182 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1769,8 +1769,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Évacuez immédiatement les zones côtières et les rives des fleuves, et réfugiez-vous dans un endroit plus sécuritaire, comme un terrain surélevé."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Restez calme et cherchez un abri à proximité."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test de messages d\'urgence"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Répondre"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Carte SIM non autorisée"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Carte SIM non configurée"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 728de05..a5c9b0f 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1420,7 +1420,7 @@
<string name="media_route_button_content_description" msgid="591703006349356016">"Caster"</string>
<string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string>
<string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Caster l\'écran sur l\'appareil"</string>
- <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils…"</string>
<string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Paramètres"</string>
<string name="media_route_controller_disconnect" msgid="8966120286374158649">"Déconnecter"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Analyse en cours..."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 09104db..8db169b 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1770,8 +1770,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Abandona de inmediato rexións costeiras e situadas na beira de ríos para dirixirte a un lugar máis seguro, como un terreo elevado."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Mantén a calma e busca refuxio cerca."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Proba de mensaxes de emerxencia"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Responder"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Non se admite a tarxeta SIM"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Non se introduciu ningunha tarxeta SIM"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f0732d4..bffede4 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -837,7 +837,7 @@
<string name="save_password_remember" msgid="6491879678996749466">"याद रखें"</string>
<string name="save_password_never" msgid="8274330296785855105">"कभी नहीं"</string>
<string name="open_permission_deny" msgid="7374036708316629800">"आपके पास इस पेज को खोलने की अनुमति नहीं है."</string>
- <string name="text_copied" msgid="4985729524670131385">"लेख की क्लिपबोर्ड पर प्रतिलिपि बनाई गई."</string>
+ <string name="text_copied" msgid="4985729524670131385">"लेख को क्लिपबोर्ड पर कॉपी किया गया."</string>
<string name="more_item_label" msgid="4650918923083320495">"अधिक"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"मेनू+"</string>
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"space"</string>
@@ -954,12 +954,12 @@
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"सभी को चुनें"</string>
<string name="cut" msgid="3092569408438626261">"काटें"</string>
- <string name="copy" msgid="2681946229533511987">"प्रतिलिपि बनाएं"</string>
+ <string name="copy" msgid="2681946229533511987">"कॉपी करें"</string>
<string name="paste" msgid="5629880836805036433">"चिपकाएं"</string>
<string name="paste_as_plain_text" msgid="5427792741908010675">"सादे पाठ के रूप में चिपकाएं"</string>
<string name="replace" msgid="5781686059063148930">"बदलें•"</string>
<string name="delete" msgid="6098684844021697789">"हटाएं"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URL की प्रतिलिपि बनाएं"</string>
+ <string name="copyUrl" msgid="2538211579596067402">"URL को कॉपी करें"</string>
<string name="selectTextMode" msgid="1018691815143165326">"लेख को चुनें"</string>
<string name="undo" msgid="7905788502491742328">"वापस लाएं"</string>
<string name="redo" msgid="7759464876566803888">"फिर से करें"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 5b741ca..7cf7507 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -567,8 +567,8 @@
<string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Կարգավորել, որ սարքի համընդհանուր պրոքսի-սերվերն օգտագործվի, երբ քաղաքականությունը միացված է: Միայն սարքի սեփականատերը կարող է կարգավորել համընդհանուր պրոքսի-սերվերը:"</string>
<string name="policylab_expirePassword" msgid="5610055012328825874">"Նշել էկր կողպ գաղտնաբ սպառումը"</string>
<string name="policydesc_expirePassword" msgid="5367525762204416046">"Փոխել էկրանի կողպման գաղտնաբառի, PIN-ի կամ նախշի փոփոխման հաճախականությունը:"</string>
- <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Կարգավորել պահոցի կոդավորումը"</string>
- <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Պահանջել, որ պահվող հավելվածների տվյալները լինեն կոդավորված:"</string>
+ <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Կարգավորել պահոցի գաղտնագրումը"</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Պահանջել, որ պահվող հավելվածների տվյալները լինեն գաղտնագրված:"</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"Կասեցնել տեսախցիկները"</string>
<string name="policydesc_disableCamera" msgid="2306349042834754597">"Կանխել բոլոր սարքերի ֆոտոխցիկների օգտագործումը:"</string>
<string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Անջատել կողպման գործառույթները"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 938b03a..426442c 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1837,8 +1837,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"יש להתפנות מיידית מאזורים הסמוכים לחופים ולנהרות למקום בטוח יותר, כגון שטח גבוה יותר."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"הישאר רגוע וחפש מחסה בקרבת מקום."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"בדיקה של הודעות חירום"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"השב"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"כרטיס ה-SIM לא מורשה"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"כרטיס ה-SIM לא מזוהה"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index affd287..52d5b0b 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1769,8 +1769,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"ອົບພະຍົບອອກຈາກເຂດຊາຍຝັ່ງທະເລ ແລະ ບໍລິເວນແມ່ນ້ຳໄປບ່ອນທີ່ປອດໄພກວ່າ ເຊັ່ນ: ບ່ອນສູງ ໂດຍທັນທີ."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"ໃຈເຢັນໆ ແລະ ຊອກຫາບ່ອນພັກຢູ່ໃກ້ໆ."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"ທົດສອບຂໍ້ຄວາມສຸກເສີນ"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"ຕອບກັບ"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ SIM"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ບໍ່ມີການນຳໃຊ້ SIM"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 48baf05..ac24366 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1837,8 +1837,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Takoj se umaknite z obalnih območij in bregov rek na varnejše mesto, na primer na višje ležeča mesta."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Ostanite mirni in poiščite zavetje v bližini."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Preskus sporočil v sili"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Odgovor"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Kartica SIM ni dovoljena"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Kartica SIM ni omogočena za uporabo"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index aa63562..48c714b 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1769,8 +1769,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Kıyı kesimlerini ve nehir kenarlarını hemen boşaltarak yüksek yerler gibi daha güvenli bölgelere gidin."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Sakin olun ve yakınlarda sığınabileceğiniz bir yer bulun."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Acil durum mesajları testi"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Yanıtla"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM\'e izin verilmiyor"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM için temel hazırlık yapılmadı"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 0a39be0..dc0395a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -999,7 +999,7 @@
<string name="whichSendApplicationNamed" msgid="2799370240005424391">"使用%1$s分享"</string>
<string name="whichSendApplicationLabel" msgid="4579076294675975354">"分享"</string>
<string name="whichSendToApplication" msgid="8272422260066642057">"通过以下应用发送"</string>
- <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"通过1$s发送"</string>
+ <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"通过%1$s发送"</string>
<string name="whichSendToApplicationLabel" msgid="8878962419005813500">"发送"</string>
<string name="whichHomeApplication" msgid="4307587691506919691">"选择主屏幕应用"</string>
<string name="whichHomeApplicationNamed" msgid="4493438593214760979">"将“%1$s”设为主屏幕应用"</string>
@@ -1769,8 +1769,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"请立即从沿海和河滨区域撤离到高地等较安全的地方。"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"请保持冷静,并寻找附近的避难地点。"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"紧急消息测试"</string>
- <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
- <skip />
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"回复"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"不受允许的 SIM 卡"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"未配置的 SIM 卡"</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 94b988e..a088a46 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -106,12 +106,6 @@
<item>@drawable/progress_large_material</item>
<item>@drawable/progress_medium_material</item>
<item>@drawable/progress_small_material</item>
- <item>@drawable/quickcontact_badge_overlay_dark</item>
- <item>@drawable/quickcontact_badge_overlay_light</item>
- <item>@drawable/quickcontact_badge_overlay_normal_dark</item>
- <item>@drawable/quickcontact_badge_overlay_normal_light</item>
- <item>@drawable/quickcontact_badge_overlay_pressed_dark</item>
- <item>@drawable/quickcontact_badge_overlay_pressed_light</item>
<item>@drawable/ratingbar_indicator_material</item>
<item>@drawable/ratingbar_material</item>
<item>@drawable/ratingbar_small_material</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 10ffa5d..be1c4b8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1990,6 +1990,10 @@
<!-- Amount of time in ms the user needs to press the relevant key to bring up the global actions dialog -->
<integer name="config_globalActionsKeyTimeout">500</integer>
+ <!-- Default width of a vertical scrollbar and height of a horizontal scrollbar.
+ Takes effect only if the scrollbar drawables have no intrinsic size. -->
+ <dimen name="config_scrollbarSize">4dp</dimen>
+
<!-- Distance that should be scrolled, per axis value, in response to a horizontal
{@link MotionEvent#ACTION_SCROLL} event. -->
<dimen name="config_horizontalScrollFactor">64dp</dimen>
@@ -2226,11 +2230,19 @@
<string-array name="config_disabledUntilUsedPreinstalledCarrierApps" translatable="false" />
<!-- The list of classes that should be added to the notification ranking pipline.
- See {@link com.android.server.notification.NotificationSignalExtractor} -->
+ See {@link com.android.server.notification.NotificationSignalExtractor}
+ If you add a new extractor to this list make sure to update
+ NotificationManagerService.handleRankingSort()-->
<string-array name="config_notificationSignalExtractors">
+ <!-- many of the following extractors depend on the notification channel, so this
+ extractor must come first -->
+ <item>com.android.server.notification.NotificationChannelExtractor</item>
+ <item>com.android.server.notification.NotificationAdjustmentExtractor</item>
+ <!-- depends on AdjustmentExtractor-->
<item>com.android.server.notification.ValidateNotificationPeople</item>
<item>com.android.server.notification.PriorityExtractor</item>
<item>com.android.server.notification.ImportanceExtractor</item>
+ <!-- depends on ImportanceExtractor-->
<item>com.android.server.notification.NotificationIntrusivenessExtractor</item>
<item>com.android.server.notification.VisibilityExtractor</item>
<item>com.android.server.notification.BadgeExtractor</item>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 18e8af7..8c26db4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -20,23 +20,13 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Suffix added to a number to signify size in bytes. -->
<string name="byteShort">B</string>
- <!-- Suffix added to a number to signify size in kilobytes (1000 bytes).
- If you retain the Latin script for the localization, please use the lowercase
- 'k', as it signifies 1000 bytes as opposed to 1024 bytes. -->
- <string name="kilobyteShort">kB</string>
- <!-- Suffix added to a number to signify size in megabytes. -->
- <string name="megabyteShort">MB</string>
- <!-- Suffix added to a number to signify size in gigabytes. -->
- <string name="gigabyteShort">GB</string>
- <!-- Suffix added to a number to signify size in terabytes. -->
- <string name="terabyteShort">TB</string>
<!-- Suffix added to a number to signify size in petabytes. -->
<string name="petabyteShort">PB</string>
- <!-- Format string used to add a suffix like "kB" or "MB" to a number
- to display a size in kilobytes, megabytes, or other size units.
- Some languages (like French) will want to add a space between
- the placeholders. -->
- <string name="fileSizeSuffix"><xliff:g id="number" example="123">%1$s</xliff:g> <xliff:g id="unit" example="MB">%2$s</xliff:g></string>
+ <!-- Format string used to add a suffix like "B" or "PB" to a number
+ to display a size in bytes or petabytes.
+ Some languages may want to remove the space between the placeholders
+ or replace it with a non-breaking space. -->
+ <string name="fileSizeSuffix"><xliff:g id="number" example="123">%1$s</xliff:g> <xliff:g id="unit" example="B">%2$s</xliff:g></string>
<!-- Used in Contacts for a field that has no label and in Note Pad
for a note with no name. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8a7d8e3..beab29a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -451,6 +451,7 @@
<java-symbol type="dimen" name="config_viewConfigurationTouchSlop" />
<java-symbol type="dimen" name="config_viewMinFlingVelocity" />
<java-symbol type="dimen" name="config_viewMaxFlingVelocity" />
+ <java-symbol type="dimen" name="config_scrollbarSize" />
<java-symbol type="dimen" name="config_horizontalScrollFactor" />
<java-symbol type="dimen" name="config_verticalScrollFactor" />
<java-symbol type="dimen" name="config_scrollFactor" />
@@ -677,7 +678,6 @@
<java-symbol type="string" name="fileSizeSuffix" />
<java-symbol type="string" name="force_close" />
<java-symbol type="string" name="gadget_host_error_inflating" />
- <java-symbol type="string" name="gigabyteShort" />
<java-symbol type="string" name="gpsNotifMessage" />
<java-symbol type="string" name="gpsNotifTicker" />
<java-symbol type="string" name="gpsNotifTitle" />
@@ -733,7 +733,6 @@
<java-symbol type="string" name="keyboardview_keycode_enter" />
<java-symbol type="string" name="keyboardview_keycode_mode_change" />
<java-symbol type="string" name="keyboardview_keycode_shift" />
- <java-symbol type="string" name="kilobyteShort" />
<java-symbol type="string" name="last_month" />
<java-symbol type="string" name="launchBrowserDefault" />
<java-symbol type="string" name="lock_to_app_toast" />
@@ -754,7 +753,6 @@
<java-symbol type="string" name="lockscreen_emergency_call" />
<java-symbol type="string" name="lockscreen_return_to_call" />
<java-symbol type="string" name="low_memory" />
- <java-symbol type="string" name="megabyteShort" />
<java-symbol type="string" name="midnight" />
<java-symbol type="string" name="mismatchPin" />
<java-symbol type="string" name="mmiComplete" />
@@ -957,7 +955,6 @@
<java-symbol type="string" name="sync_really_delete" />
<java-symbol type="string" name="sync_too_many_deletes_desc" />
<java-symbol type="string" name="sync_undo_deletes" />
- <java-symbol type="string" name="terabyteShort" />
<java-symbol type="string" name="text_copied" />
<java-symbol type="string" name="time_of_day" />
<java-symbol type="string" name="time_picker_decrement_hour_button" />
@@ -1472,6 +1469,7 @@
<java-symbol type="xml" name="global_keys" />
<java-symbol type="xml" name="default_zen_mode_config" />
<java-symbol type="xml" name="sms_7bit_translation_table" />
+ <java-symbol type="xml" name="color_extraction" />
<java-symbol type="raw" name="color_fade_vert" />
<java-symbol type="raw" name="color_fade_frag" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 86abe97..9dafa7a 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -214,7 +214,7 @@
<!-- Scrollbar attributes -->
<item name="scrollbarFadeDuration">250</item>
<item name="scrollbarDefaultDelayBeforeFade">400</item>
- <item name="scrollbarSize">10dp</item>
+ <item name="scrollbarSize">@dimen/config_scrollbarSize</item>
<item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_material</item>
<item name="scrollbarThumbVertical">@drawable/config_scrollbarThumbVertical</item>
<item name="scrollbarTrackHorizontal">@null</item>
@@ -582,7 +582,7 @@
<!-- Scrollbar attributes -->
<item name="scrollbarFadeDuration">250</item>
<item name="scrollbarDefaultDelayBeforeFade">400</item>
- <item name="scrollbarSize">10dp</item>
+ <item name="scrollbarSize">@dimen/config_scrollbarSize</item>
<item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_material</item>
<item name="scrollbarThumbVertical">@drawable/config_scrollbarThumbVertical</item>
<item name="scrollbarTrackHorizontal">@null</item>
diff --git a/core/res/res/xml/color_extraction.xml b/core/res/res/xml/color_extraction.xml
new file mode 100644
index 0000000..7d52b20
--- /dev/null
+++ b/core/res/res/xml/color_extraction.xml
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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
+ -->
+
+<colorextraction>
+ <!-- List of material color palettes in HSL -->
+ <palettes>
+ <!-- Grey scale -->
+ <palette h="0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f"
+ s="0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f"
+ l="0.08f, 0.11f, 0.14901960784313725f, 0.2f, 0.2980392156862745f, 0.4f,
+ 0.4980392156862745f, 0.6196078431372549f, 0.7176470588235294f,
+ 0.8196078431372549f, 0.9176470588235294f, 0.9490196078431372f"/>
+ <!-- All colors -->
+ <palette h="1,1,0.991,0.991,0.9833333333333333,0,0,0,
+ 0.01134380453752181,0.015625000000000003,0.024193548387096798,
+ 0.027397260273972573,0.017543859649122865"
+ s="1,1,1,1,1,1,1,0.8434782608695652,1,1,1,1,1"
+ l="0.04,0.09,0.14,0.2,0.27450980392156865,
+ 0.34901960784313724,0.4235294117647059,0.5490196078431373,
+ 0.6254901960784314,0.6862745098039216,0.7568627450980392,
+ 0.8568627450980393,0.9254901960784314"/>
+ <palette h="0.638,0.638,0.6385767790262171,0.6301169590643275,
+ 0.6223958333333334,0.6151079136690647,0.6065400843881856,
+ 0.5986964618249534,0.5910746812386157,0.5833333333333334,
+ 0.5748031496062993,0.5582010582010583"
+ s="1,1,1,1,0.9014084507042253,0.8128654970760234,
+ 0.7979797979797981,0.7816593886462883,0.778723404255319,1,1,1"
+ l="0.05,0.12,0.17450980392156862,0.2235294117647059,
+ 0.2784313725490196,0.3352941176470588,0.388235294117647,
+ 0.44901960784313727,0.5392156862745098,0.6509803921568628,
+ 0.7509803921568627,0.8764705882352941"/>
+ <palette h="0.563,0.569,0.5666,0.5669934640522876,0.5748031496062993,
+ 0.5595238095238095,0.5473118279569893,0.5393258426966292,
+ 0.5315955766192734,0.524031007751938,0.5154711673699016,
+ 0.508080808080808,0.5"
+ s="1,1,1,1,1,1,1,1,1,0.8847736625514403,1,1,1"
+ l="0.07,0.12,0.16,0.2,0.24901960784313726,
+ 0.27450980392156865,0.30392156862745096,0.34901960784313724,
+ 0.4137254901960784,0.47647058823529415,0.5352941176470588,
+ 0.6764705882352942,0.8"/>
+ <palette h="0.508,0.511,0.508,0.508,0.5082304526748972,
+ 0.5069444444444444,0.5,0.5,0.5,0.48724954462659376,
+ 0.4800347222222222,0.4755134281200632,0.4724409448818897,
+ 0.4671052631578947"
+ s="1,1,1,1,1,0.8888888888888887,0.9242424242424242,1,
+ 1,0.8133333333333332,0.7868852459016393,1,1,1"
+ l="0.04,0.06,0.08,0.12,0.1588235294117647,
+ 0.21176470588235297,0.25882352941176473,0.3,0.34901960784313724,
+ 0.44117647058823534,0.5215686274509804,0.5862745098039216,
+ 0.7509803921568627,0.8509803921568627"/>
+ <palette h="0.333,0.333,0.333,0.3333333333333333,0.3333333333333333,
+ 0.34006734006734,0.34006734006734,0.34006734006734,
+ 0.34259259259259256,0.3475783475783476,0.34767025089605735,
+ 0.3467741935483871,0.3703703703703704"
+ s="0.70,0.72,0.69,0.6703296703296703,0.728813559322034,
+ 0.5657142857142856,0.5076923076923077,0.3944223107569721,
+ 0.6206896551724138,0.8931297709923666,1,1,1"
+ l="0.05,0.08,0.14,0.1784313725490196,0.23137254901960785,
+ 0.3431372549019608,0.38235294117647056,0.49215686274509807,
+ 0.6588235294117647,0.7431372549019608,0.8176470588235294,
+ 0.8784313725490196,0.9294117647058824"/>
+ <palette h="0.161,0.163,0.163,0.162280701754386,0.15032679738562088,
+ 0.15879265091863518,0.16236559139784948,0.17443868739205526,
+ 0.17824074074074076,0.18674698795180725,0.18692449355432778,
+ 0.1946778711484594,0.18604651162790695"
+ s="1,1,1,1,1,1,1,1,1,1,1,1,1"
+ l="0.05,0.08,0.11,0.14901960784313725,0.2,
+ 0.24901960784313726,0.30392156862745096,0.3784313725490196,
+ 0.4235294117647059,0.48823529411764705,0.6450980392156863,
+ 0.7666666666666666,0.8313725490196078"/>
+ <palette h="0.108,0.105,0.105,0.105,0.10619469026548674,
+ 0.11924686192468618,0.13046448087431692,0.14248366013071895,
+ 0.1506024096385542,0.16220238095238093,0.16666666666666666,
+ 0.16666666666666666,0.162280701754386,0.15686274509803924"
+ s="1,1,1,1,1,1,1,1,1,1,1,1,1,1"
+ l="0.17,0.22,0.28,0.35,0.44313725490196076,
+ 0.46862745098039216,0.47843137254901963,0.5,0.5117647058823529,
+ 0.5607843137254902,0.6509803921568628,0.7509803921568627,
+ 0.8509803921568627,0.9"/>
+ <palette h="0.036,0.036,0.036,0.036,0.03561253561253561,
+ 0.05098039215686275,0.07516339869281045,0.09477124183006536,
+ 0.1150326797385621,0.134640522875817,0.14640522875816991,
+ 0.1582397003745319,0.15773809523809523,0.15359477124183002"
+ s="1,1,1,1,1,1,1,1,1,1,1,1,1,1"
+ l="0.19,0.26,0.34,0.39,0.4588235294117647,0.5,0.5,0.5,
+ 0.5,0.5,0.5,0.6509803921568628,0.7803921568627451,0.9"/>
+ <palette h="0.955,0.961,0.958,0.9596491228070175,0.9593837535014005,
+ 0.9514767932489452,0.943859649122807,0.9396825396825397,
+ 0.9395424836601307,0.9393939393939394,0.9362745098039216,
+ 0.9754098360655739,0.9824561403508771"
+ s="0.87,0.85,0.85,0.84070796460177,0.8206896551724138,
+ 0.7979797979797981,0.7661290322580644,0.9051724137931036,
+ 1,1,1,1,1"
+ l="0.06,0.11,0.16,0.22156862745098038,0.2843137254901961,
+ 0.388235294117647,0.48627450980392156,0.5450980392156863,
+ 0.6,0.6764705882352942,0.8,0.8803921568627451,
+ 0.9254901960784314"/>
+ <palette h="0.866,0.855,0.841025641025641,0.8333333333333334,
+ 0.8285256410256411,0.821522309711286,0.8083333333333333,
+ 0.8046594982078853,0.8005822416302766,0.7842377260981912,
+ 0.7771084337349398,0.7747747747747749"
+ s="1,1,1,1,1,1,1,1,1,
+ 0.737142857142857,0.6434108527131781,0.46835443037974644"
+ l="0.05,0.08,0.12745098039215685,0.15490196078431373,
+ 0.20392156862745098,0.24901960784313726,0.3137254901960784,
+ 0.36470588235294116,0.44901960784313727,0.6568627450980392,
+ 0.7470588235294118,0.8450980392156863"/>
+ <palette h="0.925,0.93,0.938,0.947,0.955952380952381,
+ 0.9681069958847737,0.9760479041916167,0.9873563218390804,0,0,
+ 0.009057971014492771,0.026748971193415648,
+ 0.041666666666666616,0.05303030303030304"
+ s="1,1,1,1,1,0.8350515463917526,0.6929460580912863,
+ 0.6387665198237885,0.6914893617021276,0.7583892617449666,
+ 0.8070175438596495,0.9310344827586209,1,1"
+ l="0.10,0.13,0.17,0.2,0.27450980392156865,
+ 0.3803921568627451,0.4725490196078432,0.5549019607843138,
+ 0.6313725490196078,0.707843137254902,0.7764705882352941,
+ 0.8294117647058823,0.9058823529411765,0.9568627450980391"/>
+ <palette h="0.733,0.736,0.744,0.7514619883040936,0.7679738562091503,
+ 0.7802083333333333,0.7844311377245509,0.796875,
+ 0.8165618448637316,0.8487179487179487,0.8582375478927203,
+ 0.8562091503267975,0.8666666666666667"
+ s="1,1,1,1,1,0.8163265306122449,0.6653386454183268,
+ 0.7547169811320753,0.929824561403509,0.9558823529411766,
+ 0.9560439560439562,1,1"
+ l="0.07,0.12,0.17,0.2235294117647059,0.3,
+ 0.38431372549019605,0.492156862745098,0.5843137254901961,
+ 0.6647058823529411,0.7333333333333334,0.8215686274509804,0.9,
+ 0.9411764705882353"/>
+ <palette h="0.6666666666666666,0.6666666666666666,0.6666666666666666,
+ 0.6666666666666666,0.6666666666666666,0.6666666666666666,
+ 0.6666666666666666,0.6666666666666666,0.6666666666666666,
+ 0.6666666666666666,0.6666666666666666"
+ s="0.25,0.24590163934426232,0.17880794701986752,
+ 0.14606741573033713,0.13761467889908252,0.14893617021276592,
+ 0.16756756756756758,0.20312500000000017,0.26086956521739135,
+ 0.29999999999999966,0.5000000000000004"
+ l="0.18,0.2392156862745098,0.296078431372549,
+ 0.34901960784313724,0.4274509803921569,0.5392156862745098,
+ 0.6372549019607843,0.7490196078431373,0.8196078431372549,
+ 0.8823529411764706,0.9372549019607843"/>
+ <palette h="0.938,0.944,0.952,0.961,0.9678571428571429,
+ 0.9944812362030905,0,0,
+ 0.0047348484848484815,0.00316455696202532,0,
+ 0.9980392156862745,0.9814814814814816,0.9722222222222221"
+ s="1,1,1,1,1,0.7023255813953488,0.6638655462184874,
+ 0.6521739130434782,0.7719298245614035,0.8315789473684211,
+ 0.6867469879518071,0.7264957264957265,0.8181818181818182,
+ 0.8181818181818189"
+ l="0.08,0.13,0.18,0.23,0.27450980392156865,
+ 0.4215686274509804,
+ 0.4666666666666667,0.503921568627451,0.5529411764705883,
+ 0.6274509803921569,0.6745098039215687,0.7705882352941176,
+ 0.892156862745098,0.9568627450980391"/>
+ <palette h="0.88,0.888,0.897,0.9052287581699346,0.9112021857923498,
+ 0.9270152505446624,0.9343137254901961,0.9391534391534391,
+ 0.9437984496124031,0.943661971830986,0.9438943894389439,
+ 0.9426229508196722,0.9444444444444444"
+ s="1,1,1,1,0.8133333333333332,0.7927461139896375,
+ 0.7798165137614679,0.7777777777777779,0.8190476190476191,
+ 0.8255813953488372,0.8211382113821142,0.8133333333333336,
+ 0.8000000000000006"
+ l="0.08,0.12,0.16,0.2,0.29411764705882354,
+ 0.3784313725490196,0.42745098039215684,0.4764705882352941,
+ 0.5882352941176471,0.6627450980392157,0.7588235294117647,
+ 0.8529411764705882,0.9411764705882353"/>
+ <palette h="0.669,0.680,0.6884057971014492,0.6974789915966387,
+ 0.7079889807162534,0.7154471544715447,0.7217741935483872,
+ 0.7274143302180687,0.7272727272727273,0.7258064516129031,
+ 0.7252252252252251,0.7333333333333333"
+ s="0.81,0.81,0.8214285714285715,0.6878612716763006,
+ 0.6080402010050251,0.5774647887323943,0.5391304347826086,
+ 0.46724890829694316,0.4680851063829788,0.462686567164179,
+ 0.45679012345678977,0.4545454545454551"
+ l="0.12,0.16,0.2196078431372549,0.33921568627450976,
+ 0.39019607843137255,0.4176470588235294,0.45098039215686275,
+ 0.5509803921568628,0.6313725490196078,0.7372549019607844,
+ 0.8411764705882353,0.9352941176470588"/>
+ <palette h="0.6470588235294118,0.6516666666666667,0.6464174454828661,
+ 0.6441441441441442,0.6432748538011696,0.6416666666666667,
+ 0.6402439024390243,0.6412429378531074,0.6435185185185186,
+ 0.6428571428571429"
+ s="0.8095238095238095,0.6578947368421053,0.5721925133689839,
+ 0.5362318840579711,0.5,0.4424778761061947,0.44086021505376327,
+ 0.44360902255639095,0.4499999999999997,0.4375000000000006"
+ l="0.16470588235294117,0.2980392156862745,0.36666666666666664,
+ 0.40588235294117647,0.44705882352941173,
+ 0.5568627450980392,0.6352941176470588,0.7392156862745098,
+ 0.8431372549019608,0.9372549019607843"/>
+ <palette h="0.469,0.46732026143790845,0.4718614718614719,
+ 0.4793650793650794,0.48071625344352614,0.4829683698296837,
+ 0.484375,0.4841269841269842,0.48444444444444457,
+ 0.48518518518518516,0.4907407407407408"
+ s="1,1,1,1,1,1,0.6274509803921569,0.41832669322709176,
+ 0.41899441340782106,0.4128440366972478,0.4090909090909088"
+ l="0.07,0.1,0.15098039215686274,0.20588235294117646,
+ 0.2372549019607843,0.26862745098039215,0.4,0.5078431372549019,
+ 0.6490196078431372,0.7862745098039216,0.9137254901960784"/>
+ <palette h="0.542,0.5444444444444444,0.5555555555555556,
+ 0.5555555555555556,0.553763440860215,0.5526315789473684,
+ 0.5555555555555556,0.5555555555555555,0.5555555555555556,
+ 0.5512820512820514,0.5666666666666667"
+ s="0.25,0.24590163934426232,0.19148936170212766,
+ 0.1791044776119403,0.18343195266272191,0.18446601941747576,
+ 0.1538461538461539,0.15625000000000003,0.15328467153284678,
+ 0.15662650602409653,0.151515151515151"
+ l="0.05,0.1196078431372549,0.1843137254901961,
+ 0.2627450980392157,
+ 0.33137254901960783,0.403921568627451,0.5411764705882354,
+ 0.6235294117647059,0.7313725490196079,0.8372549019607843,
+ 0.9352941176470588"/>
+ <palette h="0.022222222222222223,0.02469135802469136,0.031249999999999997,
+ 0.03947368421052631,0.04166666666666668,
+ 0.043650793650793655,0.04411764705882352,0.04166666666666652,
+ 0.04444444444444459,0.05555555555555529"
+ s="0.33333333333333337,0.2783505154639175,0.2580645161290323,
+ 0.25675675675675674,0.2528735632183908,0.17500000000000002,
+ 0.15315315315315312,0.15189873417721522,
+ 0.15789473684210534,0.15789473684210542"
+ l="0.08823529411764705,0.19019607843137254,0.2431372549019608,
+ 0.2901960784313725,0.3411764705882353,0.47058823529411764,
+ 0.5647058823529412,0.6901960784313725,0.8137254901960784,
+ 0.9254901960784314"/>
+ <palette h="0.027,0.03,0.038,0.044,0.050884955752212385,
+ 0.07254901960784313,0.0934640522875817,
+ 0.10457516339869281,0.11699346405228758,
+ 0.1255813953488372,0.1268939393939394,0.12533333333333332,
+ 0.12500000000000003,0.12777777777777777"
+ s="1,1,1,1,1,1,1,1,1,1,1,1,1,1"
+ l="0.25,0.3,0.35,0.4,0.44313725490196076,0.5,0.5,0.5,
+ 0.5,0.5784313725490196,
+ 0.6549019607843137,0.7549019607843137,0.8509803921568627,
+ 0.9411764705882353"/>
+ </palettes>
+ <blacklist>
+ <!-- Red -->
+ <range h="0, 20"
+ s="0.7, 1"
+ l="0.21, 0.79"/>
+ <range h="0, 20"
+ s="0.3, 0.7"
+ l="0.355, 0.653"/>
+ <!-- Red Orange -->
+ <range h="20, 40"
+ s="0.7, 1"
+ l="0.28, 0.643"/>
+ <range h="20, 40"
+ s="0.3, 0.7"
+ l="0.414, 0.561"/>
+ <range h="20, 40"
+ s="0, 3"
+ l="0.343, 0.584"/>
+ <!-- Orange -->
+ <range h="40, 60"
+ s="0.7, 1"
+ l="0.173, 0.349"/>
+ <range h="40, 60"
+ s="0.3, 0.7"
+ l="0.233, 0.427"/>
+ <range h="40, 60"
+ s="0, 0.3"
+ l="0.231, 0.484"/>
+ <!-- Yellow 60 -->
+ <range h="60, 80"
+ s="0.7, 1"
+ l="0.488, 0.737"/>
+ <range h="60, 80"
+ s="0.3, 0.7"
+ l="0.673, 0.837"/>
+ <!-- Yellow Green 80 -->
+ <range h="80, 100"
+ s="0.7, 1"
+ l="0.469, 0.61"/>
+ <!-- Yellow green 100 -->
+ <range h="100, 120"
+ s="0.7, 1"
+ l="0.388, 0.612"/>
+ <range h="100, 120"
+ s="0.3, 0.7"
+ l="0.424, 0.541"/>
+ <!-- Green -->
+ <range h="120, 140"
+ s="0.7, 1"
+ l="0.375, 0.52"/>
+ <range h="120, 140"
+ s="0.3, 0.7"
+ l="0.435, 0.524"/>
+ <!-- Green Blue 140 -->
+ <range h="140, 160"
+ s="0.7, 1"
+ l="0.496, 0.641"/>
+ <!-- Seaoam -->
+ <range h="160, 180"
+ s="0.7, 1"
+ l="0.496, 0.567"/>
+ <!-- Cyan -->
+ <range h="180, 200"
+ s="0.7, 1"
+ l="0.52, 0.729"/>
+ <!-- Blue -->
+ <range h="220, 240"
+ s="0.7, 1"
+ l="0.396, 0.571"/>
+ <range h="220, 240"
+ s="0.3, 0.7"
+ l="0.425, 0.551"/>
+ <!-- Blue Purple 240 -->
+ <range h="240, 260"
+ s="0.7, 1"
+ l="0.418, 0.639"/>
+ <range h="220, 240"
+ s="0.3, 0.7"
+ l="0.441, 0.576"/>
+ <!-- Blue Purple 260 -->
+ <range h="260, 280"
+ s="0.3, 1"
+ l="0.461, 0.553"/>
+ <!-- Fuchsia -->
+ <range h="300, 320"
+ s="0.7, 1"
+ l="0.484, 0.588"/>
+ <range h="300, 320"
+ s="0.3, 0.7"
+ l="0.48, 0.592"/>
+ <!-- Pink -->
+ <range h="320, 340"
+ s="0.7, 1"
+ l="0.466, 0.629"/>
+ <!-- Soft red -->
+ <range h="340, 360"
+ s="0.7, 1"
+ l="0.437, 0.596"/>
+ </blacklist>
+</colorextraction>
\ No newline at end of file
diff --git a/core/tests/coretests/README b/core/tests/coretests/README
index aced441..ea282a0 100644
--- a/core/tests/coretests/README
+++ b/core/tests/coretests/README
@@ -28,7 +28,7 @@
Next, install the resulting APK and run tests as you would normal JUnit tests:
- adb install out/target/product/.../data/app/FrameworksCoreTests/FrameworksCoreTests.apk
+ adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
adb shell am instrument -w \
com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
index 42b06f5..68b9b00 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
@@ -29,13 +29,15 @@
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
-import android.os.UserHandle;
import android.os.ParcelFileDescriptor.AutoCloseInputStream;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.provider.Settings;
import android.test.InstrumentationTestCase;
import android.util.Log;
+import libcore.io.Streams;
+
import com.google.mockwebserver.MockResponse;
import com.google.mockwebserver.MockWebServer;
@@ -54,8 +56,6 @@
import java.util.Set;
import java.util.concurrent.TimeoutException;
-import libcore.io.Streams;
-
/**
* Base class for Instrumented tests for the Download Manager.
*/
@@ -83,9 +83,6 @@
protected static final int WAIT_FOR_DOWNLOAD_POLL_TIME = 1 * 1000; // 1 second
protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 30 * 1000; // 30 seconds
- protected static final int DOWNLOAD_TO_SYSTEM_CACHE = 1;
- protected static final int DOWNLOAD_TO_DOWNLOAD_CACHE_DIR = 2;
-
// Just a few popular file types used to return from a download
protected enum DownloadFileType {
PLAINTEXT,
@@ -923,13 +920,13 @@
* @param body The body to return in the response from the server
*/
protected long doStandardEnqueue(byte[] body) throws Exception {
- return enqueueDownloadRequest(body, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
+ return enqueueDownloadRequest(body);
}
- protected long enqueueDownloadRequest(byte[] body, int location) throws Exception {
+ protected long enqueueDownloadRequest(byte[] body) throws Exception {
// Prepare the mock server with a standard response
mServer.enqueue(buildResponse(HTTP_OK, body));
- return doEnqueue(location);
+ return doEnqueue();
}
/**
@@ -938,13 +935,13 @@
* @param body The body to return in the response from the server, contained in the file
*/
protected long doStandardEnqueue(File body) throws Exception {
- return enqueueDownloadRequest(body, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
+ return enqueueDownloadRequest(body);
}
- protected long enqueueDownloadRequest(File body, int location) throws Exception {
+ protected long enqueueDownloadRequest(File body) throws Exception {
// Prepare the mock server with a standard response
mServer.enqueue(buildResponse(HTTP_OK, body));
- return doEnqueue(location);
+ return doEnqueue();
}
/**
@@ -952,16 +949,12 @@
* doing a standard enqueue request to the server.
*/
protected long doCommonStandardEnqueue() throws Exception {
- return doEnqueue(DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
+ return doEnqueue();
}
- private long doEnqueue(int location) throws Exception {
+ private long doEnqueue() throws Exception {
Uri uri = getServerUri(DEFAULT_FILENAME);
Request request = new Request(uri).setTitle(DEFAULT_FILENAME);
- if (location == DOWNLOAD_TO_SYSTEM_CACHE) {
- request.setDestinationToSystemCache();
- }
-
return mDownloadManager.enqueue(request);
}
@@ -1026,8 +1019,8 @@
/**
* Helper that does the actual basic download verification.
*/
- protected long doBasicDownload(byte[] blobData, int location) throws Exception {
- long dlRequest = enqueueDownloadRequest(blobData, location);
+ protected long doBasicDownload(byte[] blobData) throws Exception {
+ long dlRequest = enqueueDownloadRequest(blobData);
// wait for the download to complete
waitForDownloadOrTimeout(dlRequest);
diff --git a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
index d1a5d28..c1d4be0 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
@@ -23,12 +23,13 @@
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.test.suitebuilder.annotation.LargeTest;
+
import com.google.mockwebserver.MockResponse;
import java.io.File;
-import java.util.concurrent.TimeoutException;
import java.util.Iterator;
import java.util.Set;
+import java.util.concurrent.TimeoutException;
/**
* Integration tests of the DownloadManager API.
@@ -95,11 +96,11 @@
* Test a basic download of a binary file 500k in size.
*/
@LargeTest
- public void testBinaryDownloadToSystemCache() throws Exception {
+ public void testBinaryDownload() throws Exception {
int fileSize = 1024;
byte[] blobData = generateData(fileSize, DataType.BINARY);
- long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
+ long dlRequest = doBasicDownload(blobData);
verifyDownload(dlRequest, blobData);
mDownloadManager.remove(dlRequest);
}
@@ -108,11 +109,11 @@
* Tests the basic downloading of a text file 300000 bytes in size.
*/
@LargeTest
- public void testTextDownloadToSystemCache() throws Exception {
+ public void testTextDownload() throws Exception {
int fileSize = 1024;
byte[] blobData = generateData(fileSize, DataType.TEXT);
- long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
+ long dlRequest = doBasicDownload(blobData);
verifyDownload(dlRequest, blobData);
mDownloadManager.remove(dlRequest);
}
@@ -318,7 +319,7 @@
int fileSize = 1024;
byte[] blobData = generateData(fileSize, DataType.BINARY);
- long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
+ long dlRequest = doBasicDownload(blobData);
Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest));
try {
assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount());
diff --git a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
index 9fa9131..39d9a8e 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
@@ -195,7 +195,7 @@
// try to download 1MB file into /cache - and it should succeed
byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT);
- long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
+ long dlRequest = doBasicDownload(blobData);
verifyAndCleanupSingleFileDownload(dlRequest, blobData);
} finally {
if (outFile != null) {
diff --git a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
index 9bbcd3d..70a0877 100644
--- a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
+++ b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
@@ -27,7 +27,6 @@
/**
* Tests for {@link DistroFormatVersion}.
*/
-// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
public class DistroFormatVersionTest {
@Test
diff --git a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
index 2fbc9a1..eecae46 100644
--- a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
+++ b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
@@ -27,7 +27,6 @@
/**
* Tests for {@link DistroRulesVersion}.
*/
-// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
public class DistroRulesVersionTest {
@Test
diff --git a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
index 7f4819b..99abe24 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
@@ -29,7 +29,6 @@
/**
* Tests for {@link RulesState}.
*/
-// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
public class RulesStateTest {
@Test
diff --git a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
index e7a839c..91f8ebc 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
@@ -33,7 +33,6 @@
/**
* Tests for {@link RulesUpdaterContract}.
*/
-// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
public class RulesUpdaterContractTest {
@Test
diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
new file mode 100644
index 0000000..4d2a047
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.content.pm.PackageParser.Package;
+import android.os.Build;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class PackageBackwardCompatibilityTest {
+
+ private static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy";
+
+ private static final String ANDROID_TEST_RUNNER = "android.test.runner";
+
+ private static final String ANDROID_TEST_MOCK = "android.test.mock";
+
+ private Package mPackage;
+
+ private static ArrayList<String> arrayList(String... strings) {
+ ArrayList<String> list = new ArrayList<>();
+ Collections.addAll(list, strings);
+ return list;
+ }
+
+ @Before
+ public void setUp() {
+ mPackage = new Package("org.package.name");
+ mPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+
+ @Test
+ public void null_usesLibraries() {
+ PackageBackwardCompatibility.modifySharedLibraries(mPackage);
+ assertNull("usesLibraries not updated correctly", mPackage.usesLibraries);
+ }
+
+ @Test
+ public void null_usesOptionalLibraries() {
+ PackageBackwardCompatibility.modifySharedLibraries(mPackage);
+ assertNull("usesOptionalLibraries not updated correctly", mPackage.usesOptionalLibraries);
+ }
+
+ @Test
+ public void remove_org_apache_http_legacy_from_usesLibraries() {
+ mPackage.usesLibraries = arrayList(ORG_APACHE_HTTP_LEGACY);
+ PackageBackwardCompatibility.modifySharedLibraries(mPackage);
+ assertNull("usesLibraries not updated correctly", mPackage.usesLibraries);
+ }
+
+ @Test
+ public void remove_org_apache_http_legacy_from_usesOptionalLibraries() {
+ mPackage.usesOptionalLibraries = arrayList(ORG_APACHE_HTTP_LEGACY);
+ PackageBackwardCompatibility.modifySharedLibraries(mPackage);
+ assertNull("usesOptionalLibraries not updated correctly", mPackage.usesOptionalLibraries);
+ }
+
+ @Test
+ public void android_test_runner_in_usesLibraries() {
+ mPackage.usesLibraries = arrayList(ANDROID_TEST_RUNNER);
+ PackageBackwardCompatibility.modifySharedLibraries(mPackage);
+ assertEquals("usesLibraries not updated correctly",
+ arrayList(ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK),
+ mPackage.usesLibraries);
+ }
+
+ @Test
+ public void android_test_runner_in_usesOptionalLibraries() {
+ mPackage.usesOptionalLibraries = arrayList(ANDROID_TEST_RUNNER);
+ PackageBackwardCompatibility.modifySharedLibraries(mPackage);
+ assertEquals("usesOptionalLibraries not updated correctly",
+ arrayList(ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK),
+ mPackage.usesOptionalLibraries);
+ }
+
+ @Test
+ public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() {
+ mPackage.usesLibraries = arrayList(ANDROID_TEST_RUNNER);
+ mPackage.usesOptionalLibraries = arrayList(ANDROID_TEST_MOCK);
+ PackageBackwardCompatibility.modifySharedLibraries(mPackage);
+ assertEquals("usesLibraries not updated correctly",
+ arrayList(ANDROID_TEST_RUNNER),
+ mPackage.usesLibraries);
+ assertEquals("usesOptionalLibraries not updated correctly",
+ arrayList(ANDROID_TEST_MOCK),
+ mPackage.usesOptionalLibraries);
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
index 5c497b4..55092fa 100644
--- a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
@@ -34,6 +34,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.UUID;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.os.storage.VolumeInfo.STATE_MOUNTED;
@@ -90,14 +91,20 @@
File internalFile = new File(sInternalVolPath);
File adoptedFile = new File(sAdoptedVolPath);
File publicFile = new File(sPublicVolPath);
+ UUID internalUuid = UUID.randomUUID();
+ UUID adoptedUuid = UUID.randomUUID();
+ UUID publicUuid = UUID.randomUUID();
Mockito.when(storageManager.getStorageBytesUntilLow(internalFile)).thenReturn(sInternalSize);
Mockito.when(storageManager.getStorageBytesUntilLow(adoptedFile)).thenReturn(sAdoptedSize);
Mockito.when(storageManager.getStorageBytesUntilLow(publicFile)).thenReturn(sPublicSize);
- Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(internalFile), Mockito.anyInt()))
+ Mockito.when(storageManager.getUuidForPath(Mockito.eq(internalFile))).thenReturn(internalUuid);
+ Mockito.when(storageManager.getUuidForPath(Mockito.eq(adoptedFile))).thenReturn(adoptedUuid);
+ Mockito.when(storageManager.getUuidForPath(Mockito.eq(publicFile))).thenReturn(publicUuid);
+ Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(internalUuid), Mockito.anyInt()))
.thenReturn(sInternalSize);
- Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(adoptedFile), Mockito.anyInt()))
+ Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(adoptedUuid), Mockito.anyInt()))
.thenReturn(sAdoptedSize);
- Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(publicFile), Mockito.anyInt()))
+ Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(publicUuid), Mockito.anyInt()))
.thenReturn(sPublicSize);
return storageManager;
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 0001d7a..949fd16 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -158,6 +158,7 @@
Settings.Global.DEBUG_VIEW_ATTRIBUTES,
Settings.Global.DEFAULT_DNS_SERVER,
Settings.Global.DEFAULT_INSTALL_LOCATION,
+ Settings.Global.DEFAULT_RESTRICT_BACKGROUND_DATA,
Settings.Global.DESK_DOCK_SOUND,
Settings.Global.DESK_UNDOCK_SOUND,
Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index d69b1e4..56c72d2 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -786,7 +786,7 @@
@Test
public void testAssistItemIsAtIndexZero() throws Throwable {
- mActivity.getSystemService(TextClassificationManager.class).setTextClassifier(null);
+ useSystemDefaultTextClassifier();
final TextView textView = mActivity.findViewById(R.id.textview);
mActivityRule.runOnUiThread(() -> textView.setCustomSelectionActionModeCallback(
new ActionMode.Callback() {
@@ -822,6 +822,23 @@
}
@Test
+ public void testNoAssistItemForPasswordField() throws Throwable {
+ useSystemDefaultTextClassifier();
+ final TextView textView = mActivity.findViewById(R.id.textview);
+ mActivityRule.runOnUiThread(() -> {
+ textView.setInputType(
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ });
+ mInstrumentation.waitForIdleSync();
+ final String password = "afigbo@android.com";
+
+ onView(withId(R.id.textview)).perform(replaceText(password));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(password.indexOf('@')));
+ sleepForFloatingToolbarPopup();
+ assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
+ }
+
+ @Test
public void testPastePlainText_menuAction() {
initializeClipboardWithText(TextStyle.STYLED);
@@ -848,6 +865,10 @@
mActivity.getString(com.android.internal.R.string.paste_as_plain_text));
}
+ private void useSystemDefaultTextClassifier() {
+ mActivity.getSystemService(TextClassificationManager.class).setTextClassifier(null);
+ }
+
private void initializeClipboardWithText(TextStyle textStyle) {
final ClipData clip;
switch (textStyle) {
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
index 5206c9b..3825e3f 100644
--- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -23,29 +23,31 @@
import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
-import static android.support.test.espresso.matcher.ViewMatchers.withTagValue;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withTagValue;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is;
-import android.view.MenuItem;
-import android.view.ViewGroup;
-import java.util.ArrayList;
-import java.util.List;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-
import android.support.test.espresso.NoMatchingRootException;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.ViewInteraction;
+import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
import com.android.internal.widget.FloatingToolbar;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Espresso utility methods for the floating toolbar.
*/
@@ -177,6 +179,39 @@
}
/**
+ * Asserts that the floating toolbar does not contain a menu item with the specified id.
+ *
+ * @param menuItemId id of the menu item
+ * @throws AssertionError if the assertion fails
+ */
+ public static void assertFloatingToolbarDoesNotContainItem(final int menuItemId) {
+ onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
+ @Override
+ public boolean matchesSafely(View view) {
+ return !hasMenuItemWithSpecifiedId(view);
+ }
+
+ @Override
+ public void describeTo(Description description) {}
+
+ private boolean hasMenuItemWithSpecifiedId(View view) {
+ if (view.getTag() instanceof MenuItem
+ && ((MenuItem) view.getTag()).getItemId() == menuItemId) {
+ return true;
+ } else if (view instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) view;
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ if (hasMenuItemWithSpecifiedId(viewGroup.getChildAt(i))) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }));
+ }
+
+ /**
* Click specified item on the floating tool bar.
*
* @param itemLabel label of the item.
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 4e8ab31..fa3d34a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -25,8 +25,22 @@
import junit.framework.TestCase;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* Test various BatteryStatsImpl noteStart methods.
+ *
+ * Build/Install/Run: bit FrameworksCoreTests:com.android.internal.os.BatteryStatsNoteTest
+ *
+ * Alternatively,
+ * Build: m FrameworksCoreTests
+ * Install: adb install -r \
+ * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
+ * Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsNoteTest -w \
+ * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
*/
public class BatteryStatsNoteTest extends TestCase{
private static final int UID = 10500;
@@ -86,4 +100,95 @@
assertEquals(220_000, actualTime);
assertEquals(120_000, bgTime);
}
+
+
+ /** Test BatteryStatsImpl.noteUidProcessStateLocked. */
+ @SmallTest
+ public void testNoteUidProcessStateLocked() throws Exception {
+ final MockClocks clocks = new MockClocks();
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+ // map of ActivityManager process states and how long to simulate run time in each state
+ Map<Integer, Integer> stateRuntimeMap = new HashMap<Integer, Integer>();
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_TOP, 1111);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE, 1234);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 2468);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_TOP_SLEEPING, 7531);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 4455);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 1337);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_BACKUP, 90210);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_HEAVY_WEIGHT, 911);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_SERVICE, 404);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_RECEIVER, 31459);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_HOME, 1123);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_LAST_ACTIVITY, 5813);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 867);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT, 5309);
+ stateRuntimeMap.put(ActivityManager.PROCESS_STATE_CACHED_EMPTY, 42);
+
+ bi.updateTimeBasesLocked(true, false, 0, 0);
+
+ for (Map.Entry<Integer, Integer> entry : stateRuntimeMap.entrySet()) {
+ bi.noteUidProcessStateLocked(UID, entry.getKey());
+ clocks.realtime += entry.getValue();
+ clocks.uptime = clocks.realtime;
+ }
+
+ long actualRunTimeUs;
+ long expectedRunTimeMs;
+ long elapsedTimeUs = clocks.realtime * 1000;
+ BatteryStats.Uid uid = bi.getUidStats().get(UID);
+
+ // compare runtime of process states to the Uid process states they map to
+ actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP, elapsedTimeUs,
+ STATS_SINCE_CHARGED);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_TOP);
+ assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
+
+
+ actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE,
+ elapsedTimeUs, STATS_SINCE_CHARGED);
+ expectedRunTimeMs = stateRuntimeMap.get(
+ ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
+
+
+ actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING,
+ elapsedTimeUs, STATS_SINCE_CHARGED);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+ assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
+
+
+ actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND,
+ elapsedTimeUs, STATS_SINCE_CHARGED);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
+
+
+ actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND,
+ elapsedTimeUs, STATS_SINCE_CHARGED);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_BACKUP)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_HEAVY_WEIGHT)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_SERVICE)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_RECEIVER);
+ assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
+
+
+ actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_CACHED,
+ elapsedTimeUs, STATS_SINCE_CHARGED);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_HOME)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_LAST_ACTIVITY)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+ assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
+
+ // Special check for foreground service timer
+ actualRunTimeUs = uid.getForegroundServiceTimer().getTotalTimeLocked(elapsedTimeUs,
+ STATS_SINCE_CHARGED);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
index 4a23f40..27aec56 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
@@ -114,7 +114,7 @@
public void testOnTimeStarted() {
initializeCounterArrayWithDefaultValues();
mCounterArray.onTimeStarted(0, 0, 0);
- assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
@@ -150,6 +150,7 @@
@Test
public void testAddCountLocked() {
final long[] deltas = {123, 234, 345, 456};
+ when(mTimeBase.isRunning()).thenReturn(true);
mCounterArray.addCountLocked(deltas);
assertArrayEquals(deltas, mCounterArray.mCounts, "Unexpected counts");
assertArrayEquals(null, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index d586db4..57c7549 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
+import android.content.res.ResourcesImpl;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.StrictMode;
@@ -82,6 +83,12 @@
private static volatile int sDefaultDensity = -1;
+ /** @hide Used only when ResourcesImpl.TRACE_FOR_DETAILED_PRELOAD is true. */
+ public static volatile int sPreloadTracingNumInstantiatedBitmaps;
+
+ /** @hide Used only when ResourcesImpl.TRACE_FOR_DETAILED_PRELOAD is true. */
+ public static volatile long sPreloadTracingTotalBitmapsSize;
+
/**
* For backwards compatibility, allows the app layer to change the default
* density when running old apps.
@@ -128,6 +135,11 @@
NativeAllocationRegistry registry = new NativeAllocationRegistry(
Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), nativeSize);
registry.registerNativeAllocation(this, nativeBitmap);
+
+ if (ResourcesImpl.TRACE_FOR_DETAILED_PRELOAD) {
+ sPreloadTracingNumInstantiatedBitmaps++;
+ sPreloadTracingTotalBitmapsSize += nativeSize;
+ }
}
/**
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1fd5697..aa9227c 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -852,6 +852,23 @@
}
/**
+ * Distance from top of the strike-through line to the baseline. Negative values mean above the
+ * baseline. This method returns where the strike-through line should be drawn independent of if
+ * the strikeThruText bit is set at the moment.
+ * @hide
+ */
+ public float getStrikeThruPosition() {
+ return nGetStrikeThruPosition(mNativePaint, mNativeTypeface);
+ }
+
+ /**
+ * @hide
+ */
+ public float getStrikeThruThickness() {
+ return nGetStrikeThruThickness(mNativePaint, mNativeTypeface);
+ }
+
+ /**
* Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit
*
* @param strikeThruText true to set the strikeThruText bit in the paint's
@@ -2997,5 +3014,9 @@
@CriticalNative
private static native float nGetUnderlineThickness(long paintPtr, long typefacePtr);
@CriticalNative
+ private static native float nGetStrikeThruPosition(long paintPtr, long typefacePtr);
+ @CriticalNative
+ private static native float nGetStrikeThruThickness(long paintPtr, long typefacePtr);
+ @CriticalNative
private static native void nSetTextSize(long paintPtr, float textSize);
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index bfd1422..ccf9de0 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -341,12 +341,14 @@
}
}
- public boolean grant(String key, int uid) {
+ public String grant(String key, int uid) {
try {
- return mBinder.grant(key, uid) == NO_ERROR;
+ String grantAlias = mBinder.grant(key, uid);
+ if (grantAlias == "") return null;
+ return grantAlias;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
- return false;
+ return null;
}
}
diff --git a/legacy-test/jarjar-rules.txt b/legacy-test/jarjar-rules.txt
index 9077e6f..fd8555c 100644
--- a/legacy-test/jarjar-rules.txt
+++ b/legacy-test/jarjar-rules.txt
@@ -1,2 +1,3 @@
rule junit.** repackaged.junit.@1
rule android.test.** repackaged.android.test.@1
+rule com.android.internal.util.** repackaged.com.android.internal.util.@1
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 4507c50..e754daf 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -35,6 +35,13 @@
return new uirenderer::RecordingCanvas(width, height);
}
+static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness,
+ const SkPaint& paint, Canvas* canvas) {
+ const SkScalar strokeWidth = fmax(thickness, 1.0f);
+ const SkScalar bottom = top + strokeWidth;
+ canvas->drawRect(left, top, right, bottom, paint);
+}
+
void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) {
uint32_t flags;
SkDrawFilter* drawFilter = getDrawFilter();
@@ -46,7 +53,6 @@
flags = paint.getFlags();
}
if (flags & (SkPaint::kUnderlineText_ReserveFlag | SkPaint::kStrikeThruText_ReserveFlag)) {
-
const SkScalar left = x;
const SkScalar right = x + length;
if (flags & SkPaint::kUnderlineText_ReserveFlag) {
@@ -60,18 +66,15 @@
if (!metrics.hasUnderlineThickness(&thickness)) {
thickness = paint.getTextSize() * Paint::kStdUnderline_Thickness;
}
- const float strokeWidth = fmax(thickness, 1.0f);
const SkScalar top = y + position;
- const SkScalar bottom = top + strokeWidth;
- drawRect(left, top, right, bottom, paint);
+ drawStroke(left, right, top, thickness, paint, this);
}
if (flags & SkPaint::kStrikeThruText_ReserveFlag) {
const float textSize = paint.getTextSize();
- const float position = textSize * Paint::kStdStrikeThru_Offset;
- const float strokeWidth = fmax(textSize * Paint::kStdUnderline_Thickness, 1.0f);
- const SkScalar top = y + position - 0.5f * strokeWidth;
- const SkScalar bottom = y + position + 0.5f * strokeWidth;
- drawRect(left, top, right, bottom, paint);
+ const float position = textSize * Paint::kStdStrikeThru_Top;
+ const SkScalar thickness = textSize * Paint::kStdStrikeThru_Thickness;
+ const SkScalar top = y + position;
+ drawStroke(left, right, top, thickness, paint, this);
}
}
}
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 4305025..a5d83a0 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -37,6 +37,10 @@
constexpr static float kStdUnderline_Top =
kStdUnderline_Offset - 0.5f * kStdUnderline_Thickness;
+ constexpr static float kStdStrikeThru_Thickness = kStdUnderline_Thickness;
+ constexpr static float kStdStrikeThru_Top =
+ kStdStrikeThru_Offset - 0.5f * kStdStrikeThru_Thickness;
+
Paint();
Paint(const Paint& paint);
Paint(const SkPaint& paint); // NOLINT(implicit)
diff --git a/media/jni/midi/android_media_midi_MidiDevice.cpp b/media/jni/midi/android_media_midi_MidiDevice.cpp
index 4df8436..5b35453 100644
--- a/media/jni/midi/android_media_midi_MidiDevice.cpp
+++ b/media/jni/midi/android_media_midi_MidiDevice.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "Midi-JNI"
#include <android_util_Binder.h>
+#include <jni.h>
#include <midi_internal.h>
-#include <nativehelper/jni.h>
#include <utils/Log.h>
using namespace android;
diff --git a/packages/BackupRestoreConfirmation/res/values-hy/strings.xml b/packages/BackupRestoreConfirmation/res/values-hy/strings.xml
index a054068..285c15d 100644
--- a/packages/BackupRestoreConfirmation/res/values-hy/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-hy/strings.xml
@@ -25,12 +25,12 @@
<string name="allow_restore_button_label" msgid="3081286752277127827">"Վերականգնել իմ տվյալները"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Չվերականգնել"</string>
<string name="current_password_text" msgid="8268189555578298067">"Խնդրում ենք մուտքագրել ձեր ընթացիկ պահուստային գաղտնաբառը ներքևում`"</string>
- <string name="device_encryption_restore_text" msgid="1570864916855208992">"Խնդրում ենք մուտքագրել ձեր սարքի կոդավորված գաղտնաբառը ներքևում:"</string>
- <string name="device_encryption_backup_text" msgid="5866590762672844664">"Խնդրում ենք մուտքագրել ձեր սարքի կոդավորված գաղտնաբառը ներքևում: Այն նաև կօգտագործվի պահուստային արխիվի կոդավորման համար:"</string>
- <string name="backup_enc_password_text" msgid="4981585714795233099">"Խնդրում ենք մուտքագրել գաղտնաբառը` ամբողջական պահուստավորվող տվյալները կոդավորելու համար: Եթե այն դատարկ թողնեք, ապա կօգտագործվի ձեր առկա պահուստավորման գաղտնաբառը`"</string>
- <string name="backup_enc_password_optional" msgid="1350137345907579306">"Եթե ցանկանում եք կոդավորել ամբողջական պահուստավորված տվյալները, մուտքագրեք գաղտնաբառ ստորև`"</string>
- <string name="backup_enc_password_required" msgid="7889652203371654149">"Քանի որ ձեր սարքը կոդավորված է, դուք պետք է կոդավորեք նաև ձեր պահուստը: Խնդրում ենք ստորև սահմանել գաղտնաբառը՝"</string>
- <string name="restore_enc_password_text" msgid="6140898525580710823">"Եթե վերականգնվող տվյալները կոդավորված են, խնդրում ենք մուտքագրել գաղտնաբառը ստորև`"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Խնդրում ենք մուտքագրել ձեր սարքի գաղտնագրման գաղտնաբառը ներքևում:"</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Խնդրում ենք մուտքագրել ձեր սարքի գաղտնագրման գաղտնաբառը ներքևում: Այն նաև կօգտագործվի պահուստային արխիվի գաղտնագրման համար:"</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Խնդրում ենք մուտքագրել գաղտնաբառը` ամբողջական պահուստավորվող տվյալները գաղտնագրելու համար: Եթե այն դատարկ թողնեք, ապա կօգտագործվի ձեր առկա պահուստավորման գաղտնաբառը`"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Եթե ցանկանում եք գաղտնագրել ամբողջական պահուստավորված տվյալները, մուտքագրեք գաղտնաբառ ստորև`"</string>
+ <string name="backup_enc_password_required" msgid="7889652203371654149">"Քանի որ ձեր սարքը գաղտնագրված է, դուք պետք է գաղտնագրեք նաև ձեր պահուստը: Խնդրում ենք ստորև սահմանել գաղտնաբառը՝"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Եթե վերականգնվող տվյալները գաղտնագրված են, խնդրում ենք մուտքագրել գաղտնաբառը ստորև`"</string>
<string name="toast_backup_started" msgid="550354281452756121">"Պահուստավորումը սկսվում է..."</string>
<string name="toast_backup_ended" msgid="3818080769548726424">"Պահուստավորումն ավարտվեց"</string>
<string name="toast_restore_started" msgid="7881679218971277385">"Վերականգնումը մեկնարկեց..."</string>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index a7e1490..be87ed2 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -31,6 +31,7 @@
import android.net.Proxy;
import android.net.Uri;
import android.net.http.SslError;
+import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.ArrayMap;
@@ -57,6 +58,7 @@
import java.lang.InterruptedException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.util.Objects;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -286,6 +288,18 @@
return null;
}
+ private static String host(URL url) {
+ if (url == null) {
+ return null;
+ }
+ return url.getHost();
+ }
+
+ private static String sanitizeURL(URL url) {
+ // In non-Debug build, only show host to avoid leaking private info.
+ return Build.IS_DEBUGGABLE ? Objects.toString(url) : host(url);
+ }
+
private void testForCaptivePortal() {
// TODO: reuse NetworkMonitor facilities for consistent captive portal detection.
new Thread(new Runnable() {
@@ -339,6 +353,8 @@
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
getResources().getDisplayMetrics());
private int mPagesLoaded;
+ // the host of the page that this webview is currently loading. Can be null when undefined.
+ private String mHostname;
// If we haven't finished cleaning up the history, don't allow going back.
public boolean allowBack() {
@@ -346,8 +362,8 @@
}
@Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- if (url.contains(mBrowserBailOutToken)) {
+ public void onPageStarted(WebView view, String urlString, Bitmap favicon) {
+ if (urlString.contains(mBrowserBailOutToken)) {
mLaunchBrowser = true;
done(Result.WANTED_AS_IS);
return;
@@ -355,11 +371,17 @@
// The first page load is used only to cause the WebView to
// fetch the proxy settings. Don't update the URL bar, and
// don't check if the captive portal is still there.
- if (mPagesLoaded == 0) return;
+ if (mPagesLoaded == 0) {
+ return;
+ }
+ final URL url = makeURL(urlString);
+ Log.d(TAG, "onPageSarted: " + sanitizeURL(url));
+ mHostname = host(url);
// For internally generated pages, leave URL bar listing prior URL as this is the URL
// the page refers to.
- if (!url.startsWith(INTERNAL_ASSETS)) {
- getActionBar().setSubtitle(getHeaderSubtitle(url));
+ if (!urlString.startsWith(INTERNAL_ASSETS)) {
+ String subtitle = (url != null) ? getHeaderSubtitle(url) : urlString;
+ getActionBar().setSubtitle(subtitle);
}
getProgressBar().setVisibility(View.VISIBLE);
testForCaptivePortal();
@@ -401,15 +423,18 @@
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
- logMetricsEvent(MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR);
- Log.w(TAG, "SSL error (error: " + error.getPrimaryError() + " host: " +
- // Only show host to avoid leaking private info.
- Uri.parse(error.getUrl()).getHost() + " certificate: " +
- error.getCertificate() + "); displaying SSL warning.");
- final String sslErrorPage = makeSslErrorPage();
- if (VDBG) {
- Log.d(TAG, sslErrorPage);
+ final URL url = makeURL(error.getUrl());
+ final String host = host(url);
+ Log.d(TAG, String.format("SSL error: %s, url: %s, certificate: %s",
+ error.getPrimaryError(), sanitizeURL(url), error.getCertificate()));
+ if (url == null || !Objects.equals(host, mHostname)) {
+ // Ignore ssl errors for resources coming from a different hostname than the page
+ // that we are currently loading, and only cancel the request.
+ handler.cancel();
+ return;
}
+ logMetricsEvent(MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR);
+ final String sslErrorPage = makeSslErrorPage();
view.loadDataWithBaseURL(INTERNAL_ASSETS, sslErrorPage, "text/HTML", "UTF-8", null);
}
@@ -502,16 +527,13 @@
return getString(R.string.action_bar_title, info.getExtraInfo().replaceAll("^\"|\"$", ""));
}
- private String getHeaderSubtitle(String urlString) {
- URL url = makeURL(urlString);
- if (url == null) {
- return urlString;
- }
+ private String getHeaderSubtitle(URL url) {
+ String host = host(url);
final String https = "https";
if (https.equals(url.getProtocol())) {
- return https + "://" + url.getHost();
+ return https + "://" + host;
}
- return url.getHost();
+ return host;
}
private void logMetricsEvent(int event) {
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
index 0cf21d2..30c1fff 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
@@ -55,6 +55,8 @@
Log.e(LOG_TAG, "About to show UI, but no devices to show");
}
+ mPairButton = findViewById(R.id.button_pair);
+
if (getService().mRequest.isSingleDevice()) {
setContentView(R.layout.device_confirmation);
final DeviceFilterPair selectedDevice = getService().mDevicesFound.get(0);
@@ -62,9 +64,12 @@
R.string.confirmation_title,
getCallingAppName(),
selectedDevice.getDisplayName()), 0));
+ mPairButton.setOnClickListener(v -> onDeviceConfirmed(getService().mSelectedDevice));
getService().mSelectedDevice = selectedDevice;
+ onSelectionUpdate();
} else {
setContentView(R.layout.device_chooser);
+ mPairButton.setVisibility(View.GONE);
setTitle(Html.fromHtml(getString(R.string.chooser_title, getCallingAppName()), 0));
mDeviceListView = findViewById(R.id.device_list);
final DeviceDiscoveryService.DevicesAdapter adapter = getService().mDevicesAdapter;
@@ -72,16 +77,12 @@
adapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
- updatePairButtonEnabled();
+ onSelectionUpdate();
}
});
mDeviceListView.addFooterView(getProgressBar(), null, false);
}
- mPairButton = findViewById(R.id.button_pair);
- mPairButton.setOnClickListener(v -> onPairTapped(getService().mSelectedDevice));
- updatePairButtonEnabled();
-
mCancelButton = findViewById(R.id.button_cancel);
mCancelButton.setOnClickListener(v -> cancel());
}
@@ -134,15 +135,20 @@
return r.getDimensionPixelSize(R.dimen.padding);
}
- private void updatePairButtonEnabled() {
- mPairButton.setEnabled(getService().mSelectedDevice != null);
+ private void onSelectionUpdate() {
+ DeviceFilterPair selectedDevice = getService().mSelectedDevice;
+ if (mPairButton.getVisibility() != View.VISIBLE && selectedDevice != null) {
+ onDeviceConfirmed(selectedDevice);
+ } else {
+ mPairButton.setEnabled(selectedDevice != null);
+ }
}
private DeviceDiscoveryService getService() {
return DeviceDiscoveryService.sInstance;
}
- protected void onPairTapped(DeviceFilterPair selectedDevice) {
+ protected void onDeviceConfirmed(DeviceFilterPair selectedDevice) {
getService().onDeviceSelected(
getCallingPackage(), getDeviceMacAddress(selectedDevice.device));
setResult(RESULT_OK,
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 4b9415e..91e23dd 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -36,6 +36,8 @@
<uses-permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.READ_PRINT_SERVICES" />
+ <uses-permission android:name="android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS" />
<application
android:allowClearUserData="true"
diff --git a/packages/PrintSpooler/res/values-bs/strings.xml b/packages/PrintSpooler/res/values-bs/strings.xml
index d3f1b80..2e9bfa3 100644
--- a/packages/PrintSpooler/res/values-bs/strings.xml
+++ b/packages/PrintSpooler/res/values-bs/strings.xml
@@ -53,7 +53,7 @@
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Okvir za pretraživanje je prikazan"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Okvir za pretraživanje je skriven"</string>
<string name="print_add_printer" msgid="1088656468360653455">"Dodaj štampač"</string>
- <string name="print_select_printer" msgid="7388760939873368698">"Izaberite štampač"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Odaberite štampač"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"Zaboravi ovaj štampač"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> štampač je pronađen</item>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 5662703..00bb4a9 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -36,7 +36,7 @@
<string name="wifi_no_internet" msgid="3880396223819116454">"No hi ha accés a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Desat per <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"Connectada automàticament a través de: %1$s"</string>
- <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connectada automàticament a través d\'un proveïdor de valoració de la xarxa"</string>
+ <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connectada automàticament a través d\'un proveïdor de valoració de xarxes"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connectada mitjançant %1$s"</string>
<string name="available_via_passpoint" msgid="1617440946846329613">"Disponible mitjançant %1$s"</string>
<string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connectada, sense Internet"</string>
@@ -186,7 +186,7 @@
<string name="wifi_aggressive_handover" msgid="5309131983693661320">"Transferència agressiva de Wi-Fi a mòbil"</string>
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permet sempre cerca de Wi-Fi en ininerància"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Dades mòbils sempre actives"</string>
- <string name="tethering_hardware_offload" msgid="7470077827090325814">"Acceleració per maquinari per a la compartició de xarxa"</string>
+ <string name="tethering_hardware_offload" msgid="7470077827090325814">"Acceleració per maquinari per compartir la xarxa"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactiva el volum absolut"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activa el so al mateix canal"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versió AVRCP de Bluetooth"</string>
@@ -218,7 +218,7 @@
<string name="allow_mock_location_summary" msgid="317615105156345626">"Permet les ubicacions simulades"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"Inspecció d\'atributs de visualització"</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantén les dades mòbils sempre actives, fins i tot quan la Wi‑Fi està activada (per canviar de xarxa ràpidament)."</string>
- <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Fes servir l\'acceleració per maquinari per a la compartició de xarxa, si està disponible"</string>
+ <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Fes servir l\'acceleració per maquinari per compartir la xarxa, si està disponible"</string>
<string name="adb_warning_title" msgid="6234463310896563253">"Voleu permetre la depuració USB?"</string>
<string name="adb_warning_message" msgid="7316799925425402244">"La depuració USB només està indicada per a activitats de desenvolupament. Fes-la servir intercanviar dades entre l\'ordinador i el dispositiu, per instal·lar aplicacions al dispositiu sense rebre notificacions i per llegir dades de registre."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Vols revocar l\'accés a la depuració d\'USB dels ordinadors que has autoritzat anteriorment?"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index e2e0e62..4a6f12d 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -104,11 +104,11 @@
<string name="process_kernel_label" msgid="3916858646836739323">"SO Android"</string>
<string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicaciones eliminadas"</string>
<string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Usuarios y aplicaciones eliminados"</string>
- <string name="tether_settings_title_usb" msgid="6688416425801386511">"Compartir por USB"</string>
+ <string name="tether_settings_title_usb" msgid="6688416425801386511">"Compartir conexión por USB"</string>
<string name="tether_settings_title_wifi" msgid="3277144155960302049">"Zona Wi-Fi portátil"</string>
- <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Compartir por Bluetooth"</string>
- <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Compartir Internet"</string>
- <string name="tether_settings_title_all" msgid="8356136101061143841">"Compartir Internet y zona Wi-Fi"</string>
+ <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Compartir conexión por Bluetooth"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Compartir conexión"</string>
+ <string name="tether_settings_title_all" msgid="8356136101061143841">"Compartir conexión y zona Wi-Fi"</string>
<string name="managed_user_title" msgid="8109605045406748842">"Todas las aplicaciones de trabajo"</string>
<string name="user_guest" msgid="8475274842845401871">"Invitado"</string>
<string name="unknown" msgid="1592123443519355854">"Desconocido"</string>
@@ -162,7 +162,7 @@
<string name="development_settings_summary" msgid="1815795401632854041">"Establecer opciones de desarrollo de aplicaciones"</string>
<string name="development_settings_not_available" msgid="4308569041701535607">"Las opciones de desarrollador no están disponibles para este usuario"</string>
<string name="vpn_settings_not_available" msgid="956841430176985598">"Los ajustes de VPN no están disponibles para este usuario"</string>
- <string name="tethering_settings_not_available" msgid="6765770438438291012">"Los ajustes para compartir Internet no están disponibles para este usuario"</string>
+ <string name="tethering_settings_not_available" msgid="6765770438438291012">"Los ajustes para compartir conexión no están disponibles para este usuario"</string>
<string name="apn_settings_not_available" msgid="7873729032165324000">"Los ajustes del nombre de punto de acceso no están disponibles para este usuario"</string>
<string name="enable_adb" msgid="7982306934419797485">"Depuración por USB"</string>
<string name="enable_adb_summary" msgid="4881186971746056635">"Activar el modo de depuración cuando el dispositivo esté conectado por USB"</string>
@@ -186,7 +186,7 @@
<string name="wifi_aggressive_handover" msgid="5309131983693661320">"Transferencia agresiva de Wi-Fi a móvil"</string>
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir siempre búsquedas de Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Datos móviles siempre activos"</string>
- <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración por hardware para conexión mediante dispositivo portátil"</string>
+ <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración por hardware para conexión compartida"</string>
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Habilitar tono de llamada por Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versión AVRCP del Bluetooth"</string>
@@ -218,7 +218,7 @@
<string name="allow_mock_location_summary" msgid="317615105156345626">"Permitir ubicaciones simuladas"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"Inspección de atributos de vista"</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantén los datos móviles siempre activos, aunque la conexión Wi‑Fi esté activada (para cambiar de red rápidamente)."</string>
- <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Usar la aceleración por hardware para conexión mediante dispositivo portátil si está disponible"</string>
+ <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Usar la conexión compartida con aceleración por hardware si está disponible"</string>
<string name="adb_warning_title" msgid="6234463310896563253">"¿Permitir depuración por USB?"</string>
<string name="adb_warning_message" msgid="7316799925425402244">"La depuración por USB solo está indicada para actividades de desarrollo. Puedes utilizarla para intercambiar datos entre el ordenador y el dispositivo, para instalar aplicaciones en el dispositivo sin recibir notificaciones y para leer datos de registro."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"¿Quieres revocar el acceso a la depuración por USB de todos los ordenadores que has autorizado?"</string>
diff --git a/packages/SettingsLib/res/values/attrs.xml b/packages/SettingsLib/res/values/attrs.xml
index 6d852df..a8a1793 100644
--- a/packages/SettingsLib/res/values/attrs.xml
+++ b/packages/SettingsLib/res/values/attrs.xml
@@ -48,9 +48,4 @@
<attr name="footerPreferenceStyle" format="reference" />
- <declare-styleable name="PreferenceImageView">
- <attr name="maxWidth" format="dimension" />
- <attr name="maxHeight" format="dimension" />
- </declare-styleable>
-
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
index 2e77f42..c346898 100644
--- a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
+++ b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
@@ -21,6 +21,7 @@
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkTemplate.MATCH_WIFI;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.net.NetworkPolicy;
@@ -150,7 +151,7 @@
public int getPolicyCycleDay(NetworkTemplate template) {
final NetworkPolicy policy = getPolicy(template);
- return (policy != null) ? policy.cycleDay : -1;
+ return (policy != null) ? policy.cycleDay : CYCLE_NONE;
}
public void setPolicyCycleDay(NetworkTemplate template, int cycleDay, String cycleTimezone) {
@@ -204,53 +205,6 @@
writeAsync();
}
- public boolean getPolicyMetered(NetworkTemplate template) {
- NetworkPolicy policy = getPolicy(template);
- if (policy != null) {
- return policy.metered;
- } else {
- return false;
- }
- }
-
- public void setPolicyMetered(NetworkTemplate template, boolean metered) {
- boolean modified = false;
-
- NetworkPolicy policy = getPolicy(template);
- if (metered) {
- if (policy == null) {
- policy = buildDefaultPolicy(template);
- policy.metered = true;
- policy.inferred = false;
- mPolicies.add(policy);
- modified = true;
- } else if (!policy.metered) {
- policy.metered = true;
- policy.inferred = false;
- modified = true;
- }
-
- } else {
- if (policy == null) {
- // ignore when policy doesn't exist
- } else if (policy.metered) {
- policy.metered = false;
- policy.inferred = false;
- modified = true;
- }
- }
-
- // Remove legacy unquoted policies while we're here
- final NetworkTemplate unquoted = buildUnquotedNetworkTemplate(template);
- final NetworkPolicy unquotedPolicy = getPolicy(unquoted);
- if (unquotedPolicy != null) {
- mPolicies.remove(unquotedPolicy);
- modified = true;
- }
-
- if (modified) writeAsync();
- }
-
/**
* Build a revised {@link NetworkTemplate} that matches the same rule, but
* with an unquoted {@link NetworkTemplate#getNetworkId()}. Used to work
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
new file mode 100644
index 0000000..75b6696
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.development;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v4.content.LocalBroadcastManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.TwoStatePreference;
+import android.text.TextUtils;
+
+import com.android.settingslib.core.AbstractPreferenceController;
+
+public abstract class AbstractEnableAdbPreferenceController extends AbstractPreferenceController {
+ private static final String KEY_ENABLE_ADB = "enable_adb";
+ public static final String ACTION_ENABLE_ADB_STATE_CHANGED =
+ "com.android.settingslib.development.AbstractEnableAdbController."
+ + "ENABLE_ADB_STATE_CHANGED";
+
+ private SwitchPreference mPreference;
+
+ public AbstractEnableAdbPreferenceController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ if (isAvailable()) {
+ mPreference = (SwitchPreference) screen.findPreference(KEY_ENABLE_ADB);
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mContext.getSystemService(UserManager.class).isAdminUser();
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_ENABLE_ADB;
+ }
+
+ private boolean isAdbEnabled() {
+ final ContentResolver cr = mContext.getContentResolver();
+ return Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0) != 0;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ ((TwoStatePreference)preference).setChecked(isAdbEnabled());
+ }
+
+ public void enablePreference(boolean enabled) {
+ if (isAvailable()) {
+ mPreference.setEnabled(enabled);
+ }
+ }
+
+ public void resetPreference() {
+ if (mPreference.isChecked()) {
+ mPreference.setChecked(false);
+ handlePreferenceTreeClick(mPreference);
+ }
+ }
+
+ public boolean haveDebugSettings() {
+ return isAdbEnabled();
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (TextUtils.equals(KEY_ENABLE_ADB, preference.getKey())) {
+ if (!isAdbEnabled()) {
+ showConfirmationDialog((SwitchPreference) preference);
+ } else {
+ writeAdbSetting(false);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected void writeAdbSetting(boolean enabled) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.ADB_ENABLED, enabled ? 1 : 0);
+ notifyStateChanged();
+ }
+
+ protected void notifyStateChanged() {
+ LocalBroadcastManager.getInstance(mContext)
+ .sendBroadcast(new Intent(ACTION_ENABLE_ADB_STATE_CHANGED));
+ }
+
+ public abstract void showConfirmationDialog(SwitchPreference preference);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index b69232c..ed3696c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -16,6 +16,14 @@
package com.android.settingslib.net;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
+import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.telephony.TelephonyManager.SIM_STATE_READY;
+import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
+import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
+
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetworkStatsService;
@@ -29,22 +37,15 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
-import android.text.format.Time;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.R;
+import java.time.ZonedDateTime;
import java.util.Date;
import java.util.Locale;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
-import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
-import static android.telephony.TelephonyManager.SIM_STATE_READY;
-import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
-import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
-import static android.net.TrafficStats.MB_IN_BYTES;
-
public class DataUsageController {
private static final String TAG = "DataUsageController";
@@ -107,13 +108,6 @@
return null;
}
- private static Time addMonth(Time t, int months) {
- final Time rt = new Time(t);
- rt.set(t.monthDay, t.month + months, t.year);
- rt.normalize(false);
- return rt;
- }
-
public DataUsageInfo getDataUsageInfo() {
final String subscriberId = getActiveSubscriberId(mContext);
if (subscriberId == null) {
@@ -140,22 +134,11 @@
final NetworkStatsHistory history = session.getHistoryForNetwork(template, FIELDS);
final long now = System.currentTimeMillis();
final long start, end;
- if (policy != null && policy.cycleDay > 0) {
- // period = determined from cycleDay
- if (DEBUG) Log.d(TAG, "Cycle day=" + policy.cycleDay + " tz="
- + policy.cycleTimezone);
- final Time nowTime = new Time(policy.cycleTimezone);
- nowTime.setToNow();
- final Time policyTime = new Time(nowTime);
- policyTime.set(policy.cycleDay, policyTime.month, policyTime.year);
- policyTime.normalize(false);
- if (nowTime.after(policyTime)) {
- start = policyTime.toMillis(false);
- end = addMonth(policyTime, 1).toMillis(false);
- } else {
- start = addMonth(policyTime, -1).toMillis(false);
- end = policyTime.toMillis(false);
- }
+ if (policy != null) {
+ final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
+ .cycleIterator(policy).next();
+ start = cycle.first.toInstant().toEpochMilli();
+ end = cycle.second.toInstant().toEpochMilli();
} else {
// period = last 4 wks
end = now;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index ec41415..e0a88e4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -552,15 +552,11 @@
}
/**
- * Returns if the network is marked metered. Metering can be marked through its config in
- * {@link WifiConfiguration}, after connection in {@link WifiInfo}, or from a score config in
- * {@link ScoredNetwork}.
+ * Returns if the network should be considered metered.
*/
public boolean isMetered() {
return mIsScoredNetworkMetered
- || (mConfig != null && mConfig.meteredHint)
- || (mInfo != null && mInfo.getMeteredHint()
- || (mNetworkInfo != null && mNetworkInfo.isMetered()));
+ || WifiConfiguration.isMetered(mConfig, mInfo);
}
public NetworkInfo getNetworkInfo() {
@@ -729,7 +725,7 @@
}
}
- if (WifiTracker.sVerboseLogging > 0) {
+ if (WifiTracker.sVerboseLogging) {
// Add RSSI/band information for this config, what was seen up to 6 seconds ago
// verbose WiFi Logging is only turned on thru developers settings
if (mInfo != null && mNetworkInfo != null) { // This is the active connection
@@ -1170,8 +1166,9 @@
if (nc != null) {
if (nc.hasCapability(nc.NET_CAPABILITY_CAPTIVE_PORTAL)) {
- return context.getString(
- com.android.internal.R.string.network_available_sign_in);
+ int id = context.getResources()
+ .getIdentifier("network_available_sign_in", "string", "android");
+ return context.getString(id);
} else if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
return context.getString(R.string.wifi_connected_no_internet);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 5a35da9..f0ac31f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -68,11 +68,13 @@
// TODO(b/36733768): Remove flag includeSaved and includePasspoints.
private static final String TAG = "WifiTracker";
- private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean DBG() {
+ return Log.isLoggable(TAG, Log.DEBUG);
+ }
/** verbose logging flag. this flag is set thru developer debugging options
* and used so as to assist with in-the-field WiFi connectivity debugging */
- public static int sVerboseLogging = 0;
+ public static boolean sVerboseLogging;
// TODO: Allow control of this?
// Combo scans can take 5-6s to complete - set to 10s.
@@ -193,7 +195,7 @@
mConnectivityManager = connectivityManager;
// check if verbose logging has been turned on or off
- sVerboseLogging = mWifiManager.getVerboseLoggingLevel();
+ sVerboseLogging = (mWifiManager.getVerboseLoggingLevel() > 0);
mFilter = new IntentFilter();
mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
@@ -251,16 +253,12 @@
List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
updateAccessPointsLocked(newScanResults, configs);
- if (DBG) {
- Log.d(TAG, "force update - internal access point list:\n" + mInternalAccessPoints);
- }
-
// Synchronously copy access points
mMainHandler.removeMessages(MainHandler.MSG_ACCESS_POINT_CHANGED);
mMainHandler.handleMessage(
Message.obtain(mMainHandler, MainHandler.MSG_ACCESS_POINT_CHANGED));
- if (DBG) {
- Log.d(TAG, "force update - external access point list:\n" + mAccessPoints);
+ if (sVerboseLogging) {
+ Log.i(TAG, "force update - external access point list:\n" + mAccessPoints);
}
}
}
@@ -338,7 +336,7 @@
private void requestScoresForNetworkKeys(Collection<NetworkKey> keys) {
if (keys.isEmpty()) return;
- if (DBG) {
+ if (DBG()) {
Log.d(TAG, "Requesting scores for Network Keys: " + keys);
}
mNetworkScoreManager.requestScores(keys.toArray(new NetworkKey[keys.size()]));
@@ -443,19 +441,19 @@
}
if (mScanId > NUM_SCANS_TO_CONFIRM_AP_LOSS) {
- if (DBG) Log.d(TAG, "------ Dumping SSIDs that were expired on this scan ------");
+ if (DBG()) Log.d(TAG, "------ Dumping SSIDs that were expired on this scan ------");
Integer threshold = mScanId - NUM_SCANS_TO_CONFIRM_AP_LOSS;
for (Iterator<Map.Entry<String, Integer>> it = mSeenBssids.entrySet().iterator();
it.hasNext(); /* nothing */) {
Map.Entry<String, Integer> e = it.next();
if (e.getValue() < threshold) {
ScanResult result = mScanResultCache.get(e.getKey());
- if (DBG) Log.d(TAG, "Removing " + e.getKey() + ":(" + result.SSID + ")");
+ if (DBG()) Log.d(TAG, "Removing " + e.getKey() + ":(" + result.SSID + ")");
mScanResultCache.remove(e.getKey());
it.remove();
}
}
- if (DBG) Log.d(TAG, "---- Done Dumping SSIDs that were expired on this scan ----");
+ if (DBG()) Log.d(TAG, "---- Done Dumping SSIDs that were expired on this scan ----");
}
return mScanResultCache.values();
@@ -609,7 +607,7 @@
Collections.sort(accessPoints);
// Log accesspoints that were deleted
- if (DBG) {
+ if (DBG()) {
Log.d(TAG, "------ Dumping SSIDs that were not seen on this scan ------");
for (AccessPoint prevAccessPoint : mInternalAccessPoints) {
if (prevAccessPoint.getSsid() == null)
@@ -1064,7 +1062,7 @@
oldAccessPoints.put(accessPoint.mId, accessPoint);
}
- if (DBG) {
+ if (DBG()) {
Log.d(TAG, "Starting to copy AP items on the MainHandler");
}
synchronized (mLock) {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index c08dd6e..aed0270 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -298,23 +298,6 @@
}
@Test
- public void testIsMetered_returnTrueWhenNetworkInfoIsMetered() {
- WifiConfiguration configuration = createWifiConfiguration();
-
- NetworkInfo networkInfo =
- new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
- networkInfo.setMetered(true);
- AccessPoint accessPoint = new AccessPoint(mContext, configuration);
- WifiInfo wifiInfo = new WifiInfo();
- wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
- wifiInfo.setBSSID(configuration.BSSID);
- wifiInfo.setNetworkId(configuration.networkId);
- accessPoint.update(configuration, wifiInfo, networkInfo);
-
- assertThat(accessPoint.isMetered()).isTrue();
- }
-
- @Test
public void testIsMetered_returnTrueWhenScoredNetworkIsMetered() {
AccessPoint ap = createAccessPointWithScanResultCache();
diff --git a/packages/SettingsLib/tests/robotests/Android.mk b/packages/SettingsLib/tests/robotests/Android.mk
index eca2052..55b635e 100644
--- a/packages/SettingsLib/tests/robotests/Android.mk
+++ b/packages/SettingsLib/tests/robotests/Android.mk
@@ -41,7 +41,7 @@
# Include the testing libraries (JUnit4 + Robolectric libs).
LOCAL_STATIC_JAVA_LIBRARIES := \
- platform-system-robolectric \
+ mockito-robolectric-prebuilt \
truth-prebuilt
LOCAL_JAVA_LIBRARIES := \
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
new file mode 100644
index 0000000..0778b27
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settingslib.SettingLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+@RunWith(SettingLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class EnableAdbPreferenceControllerTest {
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PreferenceScreen mScreen;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private PackageManager mPackageManager;
+
+ private Context mContext;
+ private SwitchPreference mPreference;
+ private ConcreteEnableAdbPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ShadowApplication shadowContext = ShadowApplication.getInstance();
+ shadowContext.setSystemService(Context.USER_SERVICE, mUserManager);
+ mContext = spy(shadowContext.getApplicationContext());
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ mPreference = new SwitchPreference(mContext);
+ when(mScreen.findPreference(anyString())).thenReturn(mPreference);
+ mController = new ConcreteEnableAdbPreferenceController(mContext);
+ mPreference.setKey(mController.getPreferenceKey());
+ }
+
+ @Test
+ public void displayPreference_isNotAdmin_shouldRemovePreference() {
+ when(mUserManager.isAdminUser()).thenReturn(false);
+ when(mScreen.getPreferenceCount()).thenReturn(1);
+ when(mScreen.getPreference(0)).thenReturn(mPreference);
+
+ mController.displayPreference(mScreen);
+
+ verify(mScreen).removePreference(any(Preference.class));
+ }
+
+ @Test
+ public void displayPreference_isAdmin_shouldNotRemovePreference() {
+ when(mUserManager.isAdminUser()).thenReturn(true);
+
+ mController.displayPreference(mScreen);
+
+ verify(mScreen, never()).removePreference(any(Preference.class));
+ }
+
+
+ @Test
+ public void resetPreference_shouldUncheck() {
+ when(mUserManager.isAdminUser()).thenReturn(true);
+ mController.displayPreference(mScreen);
+ mPreference.setChecked(true);
+
+ mController.resetPreference();
+
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_shouldUpdateSettings() {
+ when(mUserManager.isAdminUser()).thenReturn(true);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Global.ADB_ENABLED, 1);
+ mPreference.setChecked(true);
+ mController.displayPreference(mScreen);
+
+ mController.handlePreferenceTreeClick(mPreference);
+
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Global.ADB_ENABLED, 0)).isEqualTo(0);
+ }
+
+ @Test
+ public void updateState_settingsOn_shouldCheck() {
+ when(mUserManager.isAdminUser()).thenReturn(true);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Global.ADB_ENABLED, 1);
+ mPreference.setChecked(false);
+ mController.displayPreference(mScreen);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void updateState_settingsOff_shouldUncheck() {
+ when(mUserManager.isAdminUser()).thenReturn(true);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Global.ADB_ENABLED, 0);
+ mPreference.setChecked(true);
+ mController.displayPreference(mScreen);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ class ConcreteEnableAdbPreferenceController extends AbstractEnableAdbPreferenceController {
+ public ConcreteEnableAdbPreferenceController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void showConfirmationDialog(SwitchPreference preference) {
+ // Don't show a dialog, just set setting.
+ writeAdbSetting(true);
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 0364418..e9ca753 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -18,11 +18,12 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -59,7 +60,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
@@ -100,6 +100,7 @@
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources);
+ when(mPackageManager.getResourcesForApplication((String) isNull())).thenReturn(mResources);
when(mPackageManager.getApplicationInfo(eq("abc"), anyInt()))
.thenReturn(application.getApplicationInfo());
mContentResolver = spy(application.getContentResolver());
@@ -115,7 +116,6 @@
List<Tile> outTiles = new ArrayList<>();
List<ResolveInfo> info = new ArrayList<>();
info.add(newInfo(true, testCategory));
- Map<Pair<String, String>, Tile> cache = new ArrayMap<>();
when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
.thenReturn(info);
@@ -169,7 +169,6 @@
@Test
public void getTilesForIntent_shouldSkipFilteredApps() {
- final String testCategory = "category1";
Intent intent = new Intent();
Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
List<Tile> outTiles = new ArrayList<>();
@@ -210,11 +209,9 @@
userHandleList.add(UserHandle.CURRENT);
when(mUserManager.getUserProfiles()).thenReturn(userHandleList);
- when(mPackageManager.queryIntentActivitiesAsUser(argThat(new ArgumentMatcher<Intent>() {
- public boolean matches(Object event) {
- return testAction.equals(((Intent) event).getAction());
- }
- }), anyInt(), anyInt())).thenReturn(info);
+ when(mPackageManager.queryIntentActivitiesAsUser(argThat(
+ event -> testAction.equals(event.getAction())), anyInt(), anyInt()))
+ .thenReturn(info);
List<DashboardCategory> categoryList = TileUtils.getCategories(
mContext, cache, false /* categoryDefinedInManifest */, testAction,
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index e9dadc5..4007cc9 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -187,4 +187,7 @@
<!-- default setting for Settings.System.END_BUTTON_BEHAVIOR : END_BUTTON_BEHAVIOR_SLEEP -->
<integer name="def_end_button_behavior">0x2</integer>
+
+ <!-- default setting for Settings.Global.DEFAULT_RESTRICT_BACKGROUND_DATA -->
+ <bool name="def_restrict_background_data">false</bool>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1bd58ad..15e6e45 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -32,8 +32,6 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.Cursor;
@@ -61,7 +59,7 @@
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
-import android.service.notification.NotificationListenerService;
+import android.provider.Settings.Global;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -82,7 +80,6 @@
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
@@ -2895,7 +2892,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 146;
+ private static final int SETTINGS_VERSION = 147;
private final int mUserId;
@@ -3422,6 +3419,23 @@
currentVersion = 146;
}
+ if (currentVersion == 146) {
+ // Version 146: Set the default value for DEFAULT_RESTRICT_BACKGROUND_DATA.
+ if (userId == UserHandle.USER_SYSTEM) {
+ final SettingsState globalSettings = getGlobalSettingsLocked();
+ final Setting currentSetting = globalSettings.getSettingLocked(
+ Global.DEFAULT_RESTRICT_BACKGROUND_DATA);
+ if (currentSetting.isNull()) {
+ globalSettings.insertSettingLocked(
+ Global.DEFAULT_RESTRICT_BACKGROUND_DATA,
+ getContext().getResources().getBoolean(
+ R.bool.def_restrict_background_data) ? "1" : "0",
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ }
+ currentVersion = 147;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 988b986..a8b184c 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1060,7 +1060,6 @@
}
return new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
.addExtras(sNotificationBundle)
- .setCategory(Notification.CATEGORY_SYSTEM)
.setSmallIcon(
isTv(context) ? R.drawable.ic_bug_report_black_24dp
: com.android.internal.R.drawable.stat_sys_adb)
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big.xml b/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big.xml
index fd385fc..fffa0bd 100644
--- a/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big.xml
+++ b/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big.xml
@@ -19,6 +19,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/bgProtectSecondaryTextColor"
+ android:fillColor="@android:color/white"
android:pathData="M21.35,6.49c-0.35,0.42 -0.98,0.47 -1.4,0.12l-3.07,-2.57a1,1 0,1 1,1.29 -1.53l3.07,2.57c0.42,0.35 0.47,0.98 0.11,1.41zM7.24,2.63a1,1 0,0 0,-1.41 -0.13L2.77,5.07A0.996,0.996 0,1 0,4.05 6.6l3.06,-2.57c0.43,-0.35 0.48,-0.98 0.13,-1.4zM11.75,8c-0.41,0 -0.75,0.34 -0.75,0.75v4.68c0,0.35 0.18,0.68 0.49,0.86l3.65,2.19c0.34,0.2 0.78,0.1 0.98,-0.24a0.71,0.71 0,0 0,-0.25 -0.99l-3.37,-2v-4.5c0,-0.41 -0.34,-0.75 -0.75,-0.75zM12,5.9c-3.91,0 -7.1,3.18 -7.1,7.1s3.19,7.1 7.1,7.1 7.1,-3.18 7.1,-7.1 -3.19,-7.1 -7.1,-7.1M12,4a9,9 0,1 1,-0.001 18.001A9,9 0,0 1,12 4z" />
</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index a0850f4..7d125046 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -39,6 +39,8 @@
android:layout_height="wrap_content"
android:drawablePadding="6dp"
android:drawableStart="@drawable/ic_access_alarms_big"
+ android:drawableTint="?attr/bgProtectSecondaryTextColor"
+ android:drawableTintMode="src_in"
android:textColor="?attr/bgProtectSecondaryTextColor"
android:letterSpacing="0.15"
style="@style/widget_label"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index 44fae86..ee14f3d 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -28,41 +28,46 @@
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
androidprv:layout_maxHeight="@dimen/keyguard_security_height"
android:gravity="center_horizontal|top">
- <RelativeLayout
- android:id="@+id/keyguard_clock_container"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|top">
- <TextClock
- android:id="@+id/clock_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_centerHorizontal="true"
- android:layout_alignParentTop="true"
- android:textColor="?attr/bgProtectTextColor"
- android:singleLine="true"
- style="@style/widget_big_thin"
- android:format12Hour="@string/keyguard_widget_12_hours_format"
- android:format24Hour="@string/keyguard_widget_24_hours_format"
- android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
- <com.android.systemui.ChargingView
- android:id="@+id/battery_doze"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignTop="@id/clock_view"
- android:layout_alignBottom="@id/clock_view"
- android:layout_toEndOf="@id/clock_view"
- android:visibility="invisible"
- android:src="@drawable/ic_aod_charging_24dp"
- android:contentDescription="@string/accessibility_ambient_display_charging"
- />
-
- <include layout="@layout/keyguard_status_area"
- android:id="@+id/keyguard_status_area"
+ android:orientation="vertical">
+ <RelativeLayout
+ android:id="@+id/keyguard_clock_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/clock_view" />
+ android:layout_gravity="center_horizontal|top">
+ <TextClock
+ android:id="@+id/clock_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:textColor="?attr/bgProtectTextColor"
+ android:singleLine="true"
+ style="@style/widget_big_thin"
+ android:format12Hour="@string/keyguard_widget_12_hours_format"
+ android:format24Hour="@string/keyguard_widget_24_hours_format"
+ android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
+ <com.android.systemui.ChargingView
+ android:id="@+id/battery_doze"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@id/clock_view"
+ android:layout_alignBottom="@id/clock_view"
+ android:layout_toEndOf="@id/clock_view"
+ android:visibility="invisible"
+ android:src="@drawable/ic_aod_charging_24dp"
+ android:contentDescription="@string/accessibility_ambient_display_charging"
+ />
+
+ <include layout="@layout/keyguard_status_area"
+ android:id="@+id/keyguard_status_area"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/clock_view" />
+ </RelativeLayout>
<TextView
android:id="@+id/owner_info"
@@ -72,12 +77,11 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/date_owner_info_margin"
android:layout_centerHorizontal="true"
- android:layout_below="@id/keyguard_status_area"
android:textColor="?attr/bgProtectSecondaryTextColor"
android:textSize="@dimen/widget_label_font_size"
android:letterSpacing="0.05"
android:ellipsize="marquee"
android:singleLine="true" />
- </RelativeLayout>
+ </LinearLayout>
</com.android.keyguard.KeyguardStatusView>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 451c2f7..337b68f 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -97,7 +97,7 @@
<string name="phone_label" msgid="2320074140205331708">"otvori telefon"</string>
<string name="voice_assist_label" msgid="3956854378310019854">"otvori glasovnu pomoć"</string>
<string name="camera_label" msgid="7261107956054836961">"otvori kameru"</string>
- <string name="recents_caption_resize" msgid="3517056471774958200">"Izaberite novi raspored zadataka"</string>
+ <string name="recents_caption_resize" msgid="3517056471774958200">"Odaberite novi raspored zadataka"</string>
<string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Dugme za uvećavanje u slučaju nekompatibilnosti."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Uvećani prikaz manjeg ekrana na većem ekranu."</string>
@@ -355,7 +355,7 @@
<string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Povucite gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Povucite lijevo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <string name="zen_priority_introduction" msgid="1149025108714420281">"Neće vas ometati zvukovi i vibracije, osim alarma, podsjetnika, događaja i pozivalaca koje odredite. I dalje ćete čuti sve što ste izabrali za reprodukciju, uključujući muziku, videozapise i igre."</string>
+ <string name="zen_priority_introduction" msgid="1149025108714420281">"Neće vas ometati zvukovi i vibracije, osim alarma, podsjetnika, događaja i pozivalaca koje odredite. I dalje ćete čuti sve što ste odabrali za reprodukciju, uključujući muziku, videozapise i igre."</string>
<string name="zen_alarms_introduction" msgid="4934328096749380201">"Neće vas ometati zvukovi i vibracije, osim alarma. I dalje ćete čuti sve što izaberete za reprodukciju, uključujući muziku, videozapise i igre."</string>
<string name="zen_priority_customize_button" msgid="7948043278226955063">"Prilagodi"</string>
<string name="zen_silence_introduction_voice" msgid="3948778066295728085">"Ovim se blokiraju SVI zvukovi i vibracije, uključujući alarme, muziku, videozapise i igre. I dalje ćete moći obavljati pozive."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 0e32df5..ed57564 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -314,7 +314,7 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Weitere Einstellungen"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Fertig"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Verbunden"</string>
- <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Verbunden, Akkustand <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Verbunden, Akkustand: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Verbindung wird hergestellt…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 99cbb93..c206d86 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -310,7 +310,7 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Περισσότερες ρυθμίσεις"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Τέλος"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Συνδέθηκε"</string>
- <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Σύνδεση, μπαταρία <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Συνδεδεμένη, μπαταρία <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Σύνδεση…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Πρόσδεση"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Σημείο πρόσβασης Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 5575dda..c479cfe 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -155,7 +155,7 @@
<string name="accessibility_cell_data" msgid="5326139158682385073">"Datos móviles"</string>
<string name="accessibility_cell_data_on" msgid="5927098403452994422">"Datos móviles activados"</string>
<string name="accessibility_cell_data_off" msgid="443267573897409704">"Datos móviles desactivados"</string>
- <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Compartir por Bluetooth"</string>
+ <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Compartir conexión por Bluetooth"</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"Modo avión"</string>
<string name="accessibility_vpn_on" msgid="5993385083262856059">"La red VPN está activada."</string>
<string name="accessibility_no_sims" msgid="3957997018324995781">"No hay tarjeta SIM."</string>
@@ -314,7 +314,7 @@
<string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
<string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Conectado (<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería)"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
- <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Compartir Internet"</string>
+ <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Compartir conexión"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificaciones"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Linterna"</string>
@@ -407,7 +407,7 @@
<string name="user_remove_user_message" msgid="1453218013959498039">"Se eliminarán todas las aplicaciones y todos los datos de este usuario."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Quitar"</string>
<string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
- <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el envío de datos en segundo plano"</string>
+ <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y los datos en segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar ahorro de batería"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> empezará a capturar todo lo que aparezca en la pantalla."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
@@ -589,7 +589,7 @@
<string name="battery_panel_title" msgid="7944156115535366613">"Uso de la batería"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Ahorro de batería no disponible mientras se carga el dispositivo"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"Ahorro de batería"</string>
- <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y las conexiones automáticas"</string>
+ <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Reduce el rendimiento y los datos en segundo plano"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Inicio"</string>
<string name="keyboard_key_back" msgid="2337450286042721351">"Atrás"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 122baca..820fdb3 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -312,8 +312,7 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Ezarpen gehiago"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Eginda"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Konektatuta"</string>
- <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
- <skip />
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Konektatuta. Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Konektatzen…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Konexioa partekatzea"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Sare publikoa"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 51d356e2..12ff89d 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -310,7 +310,7 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Setelan lainnya"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Selesai"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Tersambung"</string>
- <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Terhubung, daya baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"Terhubung, baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Menyambung..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Menambatkan"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 22a1464..ba5816b 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -534,7 +534,7 @@
<string name="tuner_warning" msgid="8730648121973575701">"System UI Tuner מספק לך דרכים נוספות להתאים אישית את ממשק המשתמש של Android. התכונות הניסיוניות האלה עשויות להשתנות, להתקלקל או להיעלם בגרסאות עתידיות. המשך בזהירות."</string>
<string name="tuner_persistent_warning" msgid="8597333795565621795">"התכונות הניסיוניות האלה עשויות להשתנות, להתקלקל או להיעלם בגרסאות עתידיות. המשך בזהירות."</string>
<string name="got_it" msgid="2239653834387972602">"הבנתי"</string>
- <string name="tuner_toast" msgid="603429811084428439">"מזל טוב! System UI Tuner נוסף ל\'הגדרות\'"</string>
+ <string name="tuner_toast" msgid="603429811084428439">"מזל טוב! ה-System UI Tuner נוסף ל\'הגדרות\'"</string>
<string name="remove_from_settings" msgid="8389591916603406378">"הסר מההגדרות"</string>
<string name="remove_from_settings_prompt" msgid="6069085993355887748">"האם להסיר את System UI Tuner ולהפסיק להשתמש בכל התכונות שלו?"</string>
<string name="activity_not_found" msgid="348423244327799974">"האפליקציה אינה מותקנת במכשיר"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 4065ff6..b8588d9 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -310,8 +310,7 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"更多设置"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"已连接"</string>
- <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
- <skip />
+ <string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"已连接,电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"正在连接…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"网络共享"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"热点"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 02a2e8f..38b2969 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -267,6 +267,12 @@
<!-- Doze: alpha to apply to small icons when dozing -->
<integer name="doze_small_icon_alpha">222</integer><!-- 87% of 0xff -->
+ <!-- Doze: the brightness value to use for the lower brightness AOD mode -->
+ <integer name="config_doze_aod_brightness_low">6</integer>
+
+ <!-- Doze: the brightness value to use for the higher brightness AOD mode -->
+ <integer name="config_doze_aod_brightness_high">27</integer>
+
<!-- Doze: whether the double tap sensor reports 2D touch coordinates -->
<bool name="doze_double_tap_reports_touch_coordinates">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b02f189..f060c69 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -831,6 +831,9 @@
burn-in on AOD -->
<dimen name="burn_in_prevention_offset_y">50dp</dimen>
+ <!-- padding between the notification stack and the keyguard status view when dozing -->
+ <dimen name="dozing_stack_padding">10dp</dimen>
+
<dimen name="corner_size">16dp</dimen>
<dimen name="top_padding">0dp</dimen>
<dimen name="bottom_padding">48dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 2262869..820a773 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -19,9 +19,13 @@
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.os.Handler;
+import android.os.Looper;
import android.os.UserHandle;
import android.support.v4.graphics.ColorUtils;
import android.text.TextUtils;
@@ -46,6 +50,7 @@
public class KeyguardStatusView extends GridLayout {
private static final boolean DEBUG = KeyguardConstants.DEBUG;
private static final String TAG = "KeyguardStatusView";
+ private static final int MARQUEE_DELAY_MS = 2000;
private final LockPatternUtils mLockPatternUtils;
private final AlarmManager mAlarmManager;
@@ -56,11 +61,16 @@
private TextView mOwnerInfo;
private ViewGroup mClockContainer;
private ChargingView mBatteryDoze;
+ private View mKeyguardStatusArea;
+ private Runnable mPendingMarqueeStart;
+ private Handler mHandler;
private View[] mVisibleInDoze;
private boolean mPulsing;
- private float mDarkAmount;
+ private float mDarkAmount = 0;
private int mTextColor;
+ private int mDateTextColor;
+ private int mAlarmTextColor;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -107,9 +117,29 @@
super(context, attrs, defStyle);
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mLockPatternUtils = new LockPatternUtils(getContext());
+ mHandler = new Handler(Looper.myLooper());
}
private void setEnableMarquee(boolean enabled) {
+ if (DEBUG) Log.v(TAG, "Schedule setEnableMarquee: " + (enabled ? "Enable" : "Disable"));
+ if (enabled) {
+ if (mPendingMarqueeStart == null) {
+ mPendingMarqueeStart = () -> {
+ setEnableMarqueeImpl(true);
+ mPendingMarqueeStart = null;
+ };
+ mHandler.postDelayed(mPendingMarqueeStart, MARQUEE_DELAY_MS);
+ }
+ } else {
+ if (mPendingMarqueeStart != null) {
+ mHandler.removeCallbacks(mPendingMarqueeStart);
+ mPendingMarqueeStart = null;
+ }
+ setEnableMarqueeImpl(false);
+ }
+ }
+
+ private void setEnableMarqueeImpl(boolean enabled) {
if (DEBUG) Log.v(TAG, (enabled ? "Enable" : "Disable") + " transport text marquee");
if (mAlarmStatusView != null) mAlarmStatusView.setSelected(enabled);
if (mOwnerInfo != null) mOwnerInfo.setSelected(enabled);
@@ -126,8 +156,11 @@
mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
mOwnerInfo = findViewById(R.id.owner_info);
mBatteryDoze = findViewById(R.id.battery_doze);
- mVisibleInDoze = new View[]{mBatteryDoze, mClockView};
+ mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
+ mVisibleInDoze = new View[]{mBatteryDoze, mClockView, mKeyguardStatusArea};
mTextColor = mClockView.getCurrentTextColor();
+ mDateTextColor = mDateView.getCurrentTextColor();
+ mAlarmTextColor = mAlarmStatusView.getCurrentTextColor();
boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
setEnableMarquee(shouldMarquee);
@@ -186,8 +219,7 @@
}
public int getClockBottom() {
- return mClockView.getBottom() +
- ((MarginLayoutParams) mClockView.getLayoutParams()).bottomMargin;
+ return mKeyguardStatusArea.getBottom();
}
public float getClockTextSize() {
@@ -304,6 +336,10 @@
updateDozeVisibleViews();
mBatteryDoze.setDark(dark);
mClockView.setTextColor(ColorUtils.blendARGB(mTextColor, Color.WHITE, darkAmount));
+ mDateView.setTextColor(ColorUtils.blendARGB(mDateTextColor, Color.WHITE, darkAmount));
+ int blendedAlarmColor = ColorUtils.blendARGB(mAlarmTextColor, Color.WHITE, darkAmount);
+ mAlarmStatusView.setTextColor(blendedAlarmColor);
+ mAlarmStatusView.setCompoundDrawableTintList(ColorStateList.valueOf(blendedAlarmColor));
}
public void setPulsing(boolean pulsing) {
diff --git a/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java b/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
index c382882..6296297 100644
--- a/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
@@ -14,56 +14,74 @@
package com.android.systemui;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.IDockedStackListener;
import android.view.WindowManagerGlobal;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.function.Consumer;
/**
* Utility wrapper to listen for whether or not a docked stack exists, to be
* used for things like the different overview icon in that mode.
*/
-public class DockedStackExistsListener extends IDockedStackListener.Stub {
+public class DockedStackExistsListener {
private static final String TAG = "DockedStackExistsListener";
- private final Consumer<Boolean> mCallback;
+ private static ArrayList<WeakReference<Consumer<Boolean>>> sCallbacks = new ArrayList<>();
- private DockedStackExistsListener(Consumer<Boolean> callback) {
- mCallback = callback;
+ static {
+ try {
+ WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(
+ new IDockedStackListener.Stub() {
+ @Override
+ public void onDividerVisibilityChanged(boolean b) throws RemoteException {
+
+ }
+
+ @Override
+ public void onDockedStackExistsChanged(boolean exists)
+ throws RemoteException {
+ DockedStackExistsListener.onDockedStackExistsChanged(exists);
+ }
+
+ @Override
+ public void onDockedStackMinimizedChanged(boolean b, long l, boolean b1)
+ throws RemoteException {
+
+ }
+
+ @Override
+ public void onAdjustedForImeChanged(boolean b, long l)
+ throws RemoteException {
+
+ }
+
+ @Override
+ public void onDockSideChanged(int i) throws RemoteException {
+
+ }
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed registering docked stack exists listener", e);
+ }
}
- @Override
- public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
- }
- @Override
- public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
- mCallback.accept(exists);
- }
-
- @Override
- public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
- boolean isHomeStackResizable) throws RemoteException {
- }
-
- @Override
- public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
- throws RemoteException {
- }
-
- @Override
- public void onDockSideChanged(int newDockSide) throws RemoteException {
+ private static void onDockedStackExistsChanged(boolean exists) {
+ synchronized (sCallbacks) {
+ sCallbacks.removeIf(wf -> wf.get() == null);
+ sCallbacks.forEach(wf -> wf.get().accept(exists));
+ }
}
public static void register(Consumer<Boolean> callback) {
- try {
- WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(
- new DockedStackExistsListener(callback));
- } catch (RemoteException e) {
- Log.e(TAG, "Failed registering docked stack exists listener", e);
+ synchronized (sCallbacks) {
+ sCallbacks.add(new WeakReference<>(callback));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 6571294..907a79e 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -199,7 +199,7 @@
// Load background image dimensions, if we haven't saved them yet
if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) {
// Need to load the image to get dimensions
- loadWallpaper(forDraw, true /* needsReset */);
+ loadWallpaper(forDraw, false /* needsReset */);
if (DEBUG) {
Log.d(TAG, "Reloading, redoing updateSurfaceSize later.");
}
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index 3c895ab..44cf003 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -42,7 +42,7 @@
private final GradientColors mWpHiddenColors;
public SysuiColorExtractor(Context context) {
- this(context, new Tonal(), true);
+ this(context, new Tonal(context), true);
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index e461986..28a45aa 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -23,6 +23,9 @@
import android.hardware.SensorManager;
import android.os.Handler;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+
/**
* Controls the screen brightness when dozing.
*/
@@ -34,6 +37,9 @@
private final Sensor mLightSensor;
private boolean mRegistered;
+ private final int mHighBrightness;
+ private final int mLowBrightness;
+
public DozeScreenBrightness(Context context, DozeMachine.Service service,
SensorManager sensorManager, Sensor lightSensor, Handler handler) {
mContext = context;
@@ -41,6 +47,11 @@
mSensorManager = sensorManager;
mLightSensor = lightSensor;
mHandler = handler;
+
+ mLowBrightness = context.getResources().getInteger(
+ R.integer.config_doze_aod_brightness_low);
+ mHighBrightness = context.getResources().getInteger(
+ R.integer.config_doze_aod_brightness_high);
}
@Override
@@ -67,7 +78,17 @@
@Override
public void onSensorChanged(SensorEvent event) {
if (mRegistered) {
- mDozeService.setDozeScreenBrightness(Math.max(1, (int) event.values[0]));
+ mDozeService.setDozeScreenBrightness(computeBrightness((int) event.values[0]));
+ }
+ }
+
+ private int computeBrightness(int sensorValue) {
+ // The sensor reports 0 for off, 1 for low brightness and 2 for high brightness.
+ // We currently use DozeScreenState for screen off, so we treat off as low brightness.
+ if (sensorValue >= 2) {
+ return mHighBrightness;
+ } else {
+ return mLowBrightness;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
index 4ff10e9..18fb423 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
@@ -45,6 +45,7 @@
mFragmentHostManager.getFragmentManager().beginTransaction()
.replace(id, (Fragment) mExtension.get(), mTag)
.commit();
+ mExtension.clearItem(false);
}
@Override
@@ -57,6 +58,7 @@
} catch (ClassCastException e) {
Log.e(TAG, extension.getClass().getName() + " must be a Fragment", e);
}
+ mExtension.clearItem(true);
}
public static <T> void attachExtensonToFragment(View view, String tag, int id,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
index dd3361b..686b3bb 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
@@ -29,7 +29,7 @@
*/
public class PipTouchState {
private static final String TAG = "PipTouchHandler";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private ViewConfiguration mViewConfig;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
index 5b3ec08..3d8f9ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
@@ -16,12 +16,14 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.service.quicksettings.Tile;
import android.widget.ImageView;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QSTile.Icon;
import com.android.systemui.plugins.qs.QSTile.State;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.phone.SignalDrawable;
import java.util.Objects;
@@ -35,7 +37,8 @@
public CellTileView(Context context) {
super(context);
mSignalDrawable = new SignalDrawable(mContext);
- mSignalDrawable.setDarkIntensity(isDark(mContext));
+ mSignalDrawable.setColors(QSTileImpl.getColorForState(context, Tile.STATE_UNAVAILABLE),
+ QSTileImpl.getColorForState(context, Tile.STATE_ACTIVE));
mSignalDrawable.setIntrinsicSize(context.getResources().getDimensionPixelSize(
R.dimen.qs_tile_icon_size));
}
@@ -48,10 +51,6 @@
}
}
- private static int isDark(Context context) {
- return Utils.getColorAttr(context, android.R.attr.colorForeground) == 0xff000000 ? 1 : 0;
- }
-
public static class SignalIcon extends Icon {
private final int mState;
@@ -68,7 +67,8 @@
public Drawable getDrawable(Context context) {
//TODO: Not the optimal solution to create this drawable
SignalDrawable d = new SignalDrawable(context);
- d.setDarkIntensity(isDark(context));
+ d.setColors(QSTileImpl.getColorForState(context, Tile.STATE_UNAVAILABLE),
+ QSTileImpl.getColorForState(context, Tile.STATE_ACTIVE));
d.setLevel(getState());
return d;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
index b8535a3..c356148 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
@@ -33,11 +33,12 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
-import android.util.Log;
import android.util.FloatProperty;
public class SlashDrawable extends Drawable {
+ public static final float CORNER_RADIUS = 1f;
+
private final Path mPath = new Path();
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -141,8 +142,8 @@
Matrix m = new Matrix();
final int width = getBounds().width();
final int height = getBounds().height();
- final float radiusX = scale(1f, width);
- final float radiusY = scale(1f, height);
+ final float radiusX = scale(CORNER_RADIUS, width);
+ final float radiusY = scale(CORNER_RADIUS, height);
updateRect(
scale(LEFT, width),
scale(TOP, height),
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index fa16f8e..f2ea6a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -337,7 +337,7 @@
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
- mLastConfig = Utilities.getAppConfiguration(this);
+ mLastConfig = new Configuration(Utilities.getAppConfiguration(this));
mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index a3e5e45..3e183b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -401,24 +401,6 @@
&& pm.resolveActivity(PHONE_INTENT, 0) != null;
}
- private boolean isCameraDisabledByDpm() {
- final DevicePolicyManager dpm =
- (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
- if (dpm != null && mStatusBar != null) {
- try {
- final int userId = ActivityManager.getService().getCurrentUser().id;
- final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
- final boolean disabledBecauseKeyguardSecure =
- (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
- && mStatusBar.isKeyguardSecure();
- return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
- } catch (RemoteException e) {
- Log.e(TAG, "Can't get userId", e);
- }
- }
- return false;
- }
-
private void watchForCameraPolicyChanges() {
final IntentFilter filter = new IntentFilter();
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
@@ -871,7 +853,8 @@
@Override
public IconState getIcon() {
ResolveInfo resolved = resolveCameraIntent();
- mIconState.isVisible = !isCameraDisabledByDpm() && resolved != null
+ boolean isCameraDisabled = (mStatusBar != null) && !mStatusBar.isCameraAllowedByAdmin();
+ mIconState.isVisible = !isCameraDisabled && resolved != null
&& getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
&& mUserSetupComplete;
mIconState.drawable = mContext.getDrawable(R.drawable.ic_camera_alt_24dp);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 652288d..e65bab6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -78,6 +78,7 @@
private AccelerateInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
private int mClockBottom;
private float mDarkAmount;
+ private int mDozingStackPadding;
/**
* Refreshes the dimension values.
@@ -97,6 +98,7 @@
R.dimen.burn_in_prevention_offset_x);
mBurnInPreventionOffsetY = res.getDimensionPixelSize(
R.dimen.burn_in_prevention_offset_y);
+ mDozingStackPadding = res.getDimensionPixelSize(R.dimen.dozing_stack_padding);
}
public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight,
@@ -135,7 +137,7 @@
result.stackScrollerPadding = (int) interpolate(
result.stackScrollerPadding,
- mClockBottom + y,
+ mClockBottom + y + mDozingStackPadding,
mDarkAmount);
result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 3940a15..4ffc15f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2499,6 +2499,10 @@
* @param keyguardIsShowing whether keyguard is being shown
*/
public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) {
+ if (!mStatusBar.isCameraAllowedByAdmin()) {
+ return false;
+ }
+
ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent();
String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
? null : resolveInfo.activityInfo.packageName;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
index d537cda..15ef742 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
@@ -36,6 +36,7 @@
import com.android.settingslib.R;
import com.android.settingslib.Utils;
+import com.android.systemui.qs.SlashDrawable;
public class SignalDrawable extends Drawable {
@@ -198,6 +199,11 @@
return true;
}
+ public void setColors(int background, int foreground) {
+ mPaint.setColor(background);
+ mForegroundPaint.setColor(foreground);
+ }
+
public void setDarkIntensity(float darkIntensity) {
if (darkIntensity == mOldDarkIntensity) {
return;
@@ -333,10 +339,9 @@
mForegroundPath.reset();
mFullPath.op(mCutPath, Path.Op.DIFFERENCE);
} else if (mState == STATE_AIRPLANE) {
- // Airplane mode is slashed, full-signal
- mForegroundPath.set(mFullPath);
- mFullPath.reset();
- mSlash.draw((int) height, (int) width, canvas, mForegroundPaint);
+ // Airplane mode is slashed, fully drawn background
+ mForegroundPath.reset();
+ mSlash.draw((int) height, (int) width, canvas, mPaint);
} else if (mState != STATE_CARRIER_CHANGE) {
mForegroundPath.reset();
int sigWidth = Math.round(calcFit(mLevel / (mNumLevels - 1)) * (width - 2 * padding));
@@ -473,6 +478,7 @@
void draw(int height, int width, @NonNull Canvas canvas, Paint paint) {
Matrix m = new Matrix();
+ final float radius = scale(SlashDrawable.CORNER_RADIUS, width);
updateRect(
scale(LEFT, width),
scale(TOP, height),
@@ -481,7 +487,7 @@
mPath.reset();
// Draw the slash vertically
- mPath.addRect(mSlashRect, Direction.CW);
+ mPath.addRoundRect(mSlashRect, radius, radius, Direction.CW);
m.setRotate(ROTATION, width / 2, height / 2);
mPath.transform(m);
canvas.drawPath(mPath, paint);
@@ -491,7 +497,7 @@
mPath.transform(m);
m.setTranslate(mSlashRect.width(), 0);
mPath.transform(m);
- mPath.addRect(mSlashRect, Direction.CW);
+ mPath.addRoundRect(mSlashRect, radius, radius, Direction.CW);
m.setRotate(ROTATION, width / 2, height / 2);
mPath.transform(m);
canvas.clipOutPath(mPath);
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 3f5f4da..2afdab8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1,5 +1,3 @@
-
-
/*
* Copyright (C) 2010 The Android Open Source Project
*
@@ -104,6 +102,7 @@
import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.service.vr.IVrManager;
@@ -565,7 +564,7 @@
}};
private boolean mWaitingForKeyguardExit;
- private boolean mDozing;
+ protected boolean mDozing;
private boolean mDozingRequested;
protected boolean mScrimSrcModeEnabled;
@@ -5280,6 +5279,18 @@
}
}
+ boolean isCameraAllowedByAdmin() {
+ if (mDevicePolicyManager.getCameraDisabled(null, mCurrentUserId)) {
+ return false;
+ } else if (isKeyguardShowing() && isKeyguardSecure()) {
+ // Check if the admin has disabled the camera specifically for the keyguard
+ return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUserId)
+ & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
+ }
+
+ return true;
+ }
+
public void notifyFpAuthModeChanged() {
updateDozing();
}
@@ -5303,6 +5314,10 @@
}
public boolean isKeyguardShowing() {
+ if (mStatusBarKeyguardViewManager == null) {
+ Slog.i(TAG, "isKeyguardShowing() called before startKeyguard(), returning true");
+ return true;
+ }
return mStatusBarKeyguardViewManager.isShowing();
}
@@ -5578,6 +5593,10 @@
private Set<String> mNonBlockablePkgs;
+ public boolean isDeviceInteractive() {
+ return mDeviceInteractive;
+ }
+
@Override // NotificationData.Environment
public boolean isDeviceProvisioned() {
return mDeviceProvisionedController.isDeviceProvisioned();
@@ -7227,7 +7246,12 @@
return false;
}
- if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
+ if (!isDozing() && mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
+ if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
+ return false;
+ }
+
+ if (isDozing() && mNotificationData.shouldSuppressScreenOff(sbn.getKey())) {
if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
index 40e3806..ede8411 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
@@ -38,6 +38,13 @@
* (like configuration) may have changed.
*/
T reload();
+
+ /**
+ * Null out the cached item for the purpose of memory saving, should only be done
+ * when any other references are already gotten.
+ * @param isDestroyed
+ */
+ void clearItem(boolean isDestroyed);
}
interface ExtensionBuilder<T> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
index b79137e..cc10775 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
@@ -26,6 +26,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.leak.LeakDetector;
import java.util.ArrayList;
import java.util.Collections;
@@ -146,7 +147,18 @@
return get();
}
+ @Override
+ public void clearItem(boolean isDestroyed) {
+ if (isDestroyed && mItem != null) {
+ Dependency.get(LeakDetector.class).trackGarbage(mItem);
+ }
+ mItem = null;
+ }
+
private void notifyChanged() {
+ if (mItem != null) {
+ Dependency.get(LeakDetector.class).trackGarbage(mItem);
+ }
mItem = null;
for (int i = 0; i < mProducers.size(); i++) {
final T item = mProducers.get(i).get();
@@ -169,7 +181,7 @@
}
public void addTunerFactory(TunerFactory<T> factory, String[] keys) {
- mProducers.add(new TunerItem(factory, factory.keys()));
+ mProducers.add(new TunerItem(factory, keys));
}
public void addUiMode(int uiMode, Supplier<T> mode) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index ba9e60a..021f9c4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -21,6 +21,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import com.android.systemui.Dependency;
@@ -84,12 +85,15 @@
// TODO(b/35345376): Turn this back on for debuggable builds after known leak fixed.
private static final boolean ENABLED = Build.IS_DEBUGGABLE
&& SystemProperties.getBoolean("debug.enable_leak_reporting", false);
+ private static final String FORCE_ENABLE = "sysui_force_garbage_monitor";
private GarbageMonitor mGarbageMonitor;
@Override
public void start() {
- if (!ENABLED) {
+ boolean forceEnable = Settings.Secure.getInt(mContext.getContentResolver(),
+ FORCE_ENABLE, 0) != 0;
+ if (!ENABLED && !forceEnable) {
return;
}
mGarbageMonitor = Dependency.get(GarbageMonitor.class);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Util.java b/packages/SystemUI/src/com/android/systemui/volume/Util.java
index a46a44d..c6d6218 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Util.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Util.java
@@ -78,6 +78,7 @@
}
public static String mediaMetadataToString(MediaMetadata metadata) {
+ if (metadata == null) return null;
return metadata.getDescription().toString();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index eaad2f9..103eb6e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -48,8 +48,10 @@
import com.android.internal.annotations.GuardedBy;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -89,11 +91,12 @@
private final W mWorker;
private final Context mContext;
private AudioManager mAudio;
+ protected StatusBar mStatusBar;
private final NotificationManager mNoMan;
private final SettingObserver mObserver;
private final Receiver mReceiver = new Receiver();
private final MediaSessions mMediaSessions;
- private final C mCallbacks = new C();
+ protected C mCallbacks = new C();
private final State mState = new State();
private final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
private final Vibrator mVibrator;
@@ -123,6 +126,7 @@
mReceiver.init();
mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
+ updateStatusBar();
boolean accessibilityVolumeStreamActive = context.getSystemService(
AccessibilityManager.class).isAccessibilityVolumeStreamActive();
@@ -326,8 +330,17 @@
return changed;
}
- private boolean onVolumeChangedW(int stream, int flags) {
- final boolean showUI = (flags & AudioManager.FLAG_SHOW_UI) != 0;
+ private void updateStatusBar() {
+ if (mStatusBar == null) {
+ mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
+ }
+ }
+
+ boolean onVolumeChangedW(int stream, int flags) {
+ updateStatusBar();
+
+ final boolean showUI = (mStatusBar != null && mStatusBar.isDeviceInteractive()) &&
+ ((flags & AudioManager.FLAG_SHOW_UI) != 0);
final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
@@ -638,7 +651,7 @@
}
}
- private final class C implements Callbacks {
+ class C implements Callbacks {
private final HashMap<Callbacks, Handler> mCallbackMap = new HashMap<>();
public void add(Callbacks callback, Handler handler) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 2527c6b..22fb710 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -178,7 +178,13 @@
@Override
public void destroy() {
+ mAccessibility.destroy();
mController.removeCallback(mControllerCallbackH);
+ if (mZenFooter != null) {
+ mZenFooter.cleanup();
+ }
+ Dependency.get(TunerService.class).removeTunable(this);
+ mHandler.removeCallbacksAndMessages(null);
}
private void initDialog() {
@@ -1240,16 +1246,14 @@
}
});
mDialogView.setAccessibilityDelegate(this);
- mAccessibilityMgr.addAccessibilityStateChangeListener(
- new AccessibilityStateChangeListener() {
- @Override
- public void onAccessibilityStateChanged(boolean enabled) {
- updateFeedbackEnabled();
- }
- });
+ mAccessibilityMgr.addAccessibilityStateChangeListener(mListener);
updateFeedbackEnabled();
}
+ public void destroy() {
+ mAccessibilityMgr.removeAccessibilityStateChangeListener(mListener);
+ }
+
@Override
public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
AccessibilityEvent event) {
@@ -1272,6 +1276,9 @@
}
return false;
}
+
+ private final AccessibilityStateChangeListener mListener =
+ enabled -> updateFeedbackEnabled();
}
private static class VolumeRow {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
index 690186e..d0f0bfd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
@@ -48,7 +48,8 @@
@Test
public void getColors_usesGreyIfWallpaperNotVisible() {
- SysuiColorExtractor extractor = new SysuiColorExtractor(getContext(), new Tonal(), false);
+ SysuiColorExtractor extractor = new SysuiColorExtractor(getContext(),
+ new Tonal(getContext()), false);
simulateEvent(extractor);
extractor.setWallpaperVisible(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 514dc8b..fe3221a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -38,11 +38,13 @@
import com.android.systemui.utils.hardware.FakeSensorManager;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
+@Ignore
public class DozeScreenBrightnessTest extends SysuiTestCase {
DozeServiceFake mServiceFake;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 8a4983c..c33897e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -334,6 +334,83 @@
}
@Test
+ public void testShouldPeek_suppressedScreenOn_dozing() {
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
+ when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
+ when(mSystemServicesProxy.isDreaming()).thenReturn(false);
+ when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
+
+ mStatusBar.mDozing = true;
+ when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(true);
+ when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(false);
+
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+ UserHandle.of(0), null, 0);
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+
+ assertTrue(mStatusBar.shouldPeek(entry, sbn));
+ }
+
+ @Test
+ public void testShouldPeek_suppressedScreenOn_noDoze() {
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
+ when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
+ when(mSystemServicesProxy.isDreaming()).thenReturn(false);
+ when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
+
+ mStatusBar.mDozing = false;
+ when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(true);
+ when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(false);
+
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+ UserHandle.of(0), null, 0);
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ assertFalse(mStatusBar.shouldPeek(entry, sbn));
+ }
+ @Test
+ public void testShouldPeek_suppressedScreenOff_dozing() {
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
+ when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
+ when(mSystemServicesProxy.isDreaming()).thenReturn(false);
+ when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
+
+ mStatusBar.mDozing = true;
+ when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(false);
+ when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(true);
+
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+ UserHandle.of(0), null, 0);
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ assertFalse(mStatusBar.shouldPeek(entry, sbn));
+ }
+
+ @Test
+ public void testShouldPeek_suppressedScreenOff_noDoze() {
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
+ when(mNotificationData.shouldFilterOut(any())).thenReturn(false);
+ when(mSystemServicesProxy.isDreaming()).thenReturn(false);
+ when(mNotificationData.getImportance(any())).thenReturn(IMPORTANCE_HIGH);
+
+ mStatusBar.mDozing = false;
+ when(mNotificationData.shouldSuppressScreenOn(any())).thenReturn(false);
+ when(mNotificationData.shouldSuppressScreenOff(any())).thenReturn(true);
+
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+ UserHandle.of(0), null, 0);
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ assertTrue(mStatusBar.shouldPeek(entry, sbn));
+ }
+
+
+ @Test
public void testLogHidden() {
try {
mStatusBar.handleVisibleToUserChanged(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
index daf7547..586a424 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
@@ -100,6 +100,11 @@
}
@Override
+ public void clearItem(boolean isDestroyed) {
+
+ }
+
+ @Override
public Context getContext() {
return null;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/UtilTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/UtilTest.java
new file mode 100644
index 0000000..6b20a1e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/UtilTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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.volume;
+
+import android.media.MediaMetadata;
+import android.support.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+@SmallTest
+public class UtilTest extends SysuiTestCase {
+
+ @Test
+ public void testMediaMetadataToString_null() {
+ Assert.assertEquals(null, Util.mediaMetadataToString(null));
+ }
+
+ @Test
+ public void testMediaMetadataToString_notNull() {
+ Assert.assertNotNull(Util.mediaMetadataToString(new MediaMetadata.Builder().build()));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
new file mode 100644
index 0000000..8060f5b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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.volume;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.support.test.filters.SmallTest;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@SmallTest
+public class VolumeDialogControllerImplTest extends SysuiTestCase {
+
+ TestableVolumeDialogControllerImpl mVolumeController;
+ VolumeDialogControllerImpl.C mCallback;
+ StatusBar mStatusBar;
+
+ @Before
+ public void setup() throws Exception {
+ mCallback = mock(VolumeDialogControllerImpl.C.class);
+ mStatusBar = mock(StatusBar.class);
+ mVolumeController = new TestableVolumeDialogControllerImpl(mContext, mCallback, mStatusBar);
+ }
+
+ @Test
+ public void testVolumeChangeW_deviceNotInteractiveAOD() {
+ when(mStatusBar.isDeviceInteractive()).thenReturn(false);
+ mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
+ verify(mCallback, never()).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
+ }
+
+ @Test
+ public void testVolumeChangeW_deviceInteractive() {
+ when(mStatusBar.isDeviceInteractive()).thenReturn(true);
+ mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
+ verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
+ }
+
+ static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
+ public TestableVolumeDialogControllerImpl(Context context, C callback, StatusBar s) {
+ super(context);
+ mCallbacks = callback;
+ mStatusBar = s;
+ }
+ }
+
+}
diff --git a/proto/src/ipconnectivity.proto b/proto/src/ipconnectivity.proto
index 76c5418..885896f 100644
--- a/proto/src/ipconnectivity.proto
+++ b/proto/src/ipconnectivity.proto
@@ -23,7 +23,7 @@
// It is not intended to map one to one to the TRANSPORT_* constants defined in
// android.net.NetworkCapabilities. Instead it is intended to be used as
// a dimension field for metrics events and aggregated metrics.
-// Next tag: 7
+// Next tag: 10
enum LinkLayer {
// An unknown link layer technology.
UNKNOWN = 0;
@@ -32,6 +32,9 @@
CELLULAR = 2;
ETHERNET = 3;
WIFI = 4;
+ WIFI_P2P = 7;
+ WIFI_NAN = 8; // Also known as WiFi Aware
+ LOWPAN = 9;
// Indicates that the link layer dimension is not relevant for the metrics or
// event considered.
@@ -47,16 +50,18 @@
optional int32 value = 2;
};
-// Logs changes in the system default network. Changes can be 1) acquiring a
-// default network with no previous default, 2) a switch of the system default
-// network to a new default network, 3) a loss of the system default network.
-// This message is associated to android.net.metrics.DefaultNetworkEvent.
+// An event record when the system default network disconnects or the system
+// switches to a new default network.
+// Next tag: 10.
message DefaultNetworkEvent {
- // A value of 0 means this is a loss of the system default network.
- optional NetworkId network_id = 1;
- // A value of 0 means there was no previous default network.
- optional NetworkId previous_network_id = 2;
+ // Reason why this network stopped being the default.
+ enum LostReason {
+ UNKNOWN = 0;
+ OUTSCORED = 1;
+ INVALIDATION = 2;
+ DISCONNECT = 3;
+ };
// Whether the network supports IPv4, IPv6, or both.
enum IPSupport {
@@ -66,17 +71,52 @@
DUAL = 3;
};
+ // Duration in milliseconds when this network was the default.
+ // Since version 4
+ optional int64 default_network_duration_ms = 5;
+
+ // Duration in milliseconds without a default network before this network
+ // became the default.
+ // Since version 4
+ optional int64 no_default_network_duration_ms = 6;
+
+ // Network score of this network when it became the default network.
+ // Since version 4
+ optional int64 initial_score = 7;
+
+ // Network score of this network when it stopped being the default network.
+ // Since version 4
+ optional int64 final_score = 8;
+
+ // Best available information about IP support of this default network.
+ // Since version 4
+ optional IPSupport ip_support = 9;
+
+
+ // Deprecated fields
+
+ // A value of 0 means this is a loss of the system default network.
+ // Deprecated since version 3. Replaced by top level network_id.
+ optional NetworkId network_id = 1 [deprecated = true];
+
+ // A value of 0 means there was no previous default network.
+ // Deprecated since version 3. Replaced by previous_default_network_id.
+ optional NetworkId previous_network_id = 2 [deprecated = true];
+
// Best available information about IP support of the previous network when
// disconnecting or switching to a new default network.
- optional IPSupport previous_network_ip_support = 3;
+ // Deprecated since version 3. Replaced by ip_support field.
+ optional IPSupport previous_network_ip_support = 3 [deprecated = true];
// The transport types of the new default network, represented by
// TRANSPORT_* constants as defined in NetworkCapabilities.
- repeated int32 transport_types = 4;
+ // Deprecated since version 3. Replaced by top-level transports field.
+ repeated int32 transport_types = 4 [deprecated = true];
};
// Logs IpReachabilityMonitor probe events and NUD_FAILED events.
// This message is associated to android.net.metrics.IpReachabilityEvent.
+// Next tag: 3.
message IpReachabilityEvent {
// The interface name (wlan, rmnet, lo, ...) on which the probe was sent.
// Deprecated since version 2, to be replaced by link_layer field.
@@ -91,6 +131,7 @@
// Logs NetworkMonitor and ConnectivityService events related to the state of
// a network: connection, evaluation, validation, lingering, and disconnection.
// This message is associated to android.net.metrics.NetworkEvent.
+// Next tag: 4.
message NetworkEvent {
// The id of the network on which this event happened.
// Deprecated since version 3.
@@ -108,6 +149,7 @@
// Logs individual captive portal probing events that are performed when
// evaluating or reevaluating networks for Internet connectivity.
// This message is associated to android.net.metrics.ValidationProbeEvent.
+// Next tag: 5.
message ValidationProbeEvent {
// The id of the network for which the probe was sent.
// Deprecated since version 3.
@@ -124,26 +166,64 @@
optional int32 probe_result = 4;
}
-// Logs DNS lookup latencies. Repeated fields must have the same length.
+// Logs DNS lookup latencies.
// This message is associated to android.net.metrics.DnsEvent.
-// Deprecated since version 2.
+// Next tag: 11
message DNSLookupBatch {
+
+ // The time it took for successful DNS lookups to complete.
+ // The number of repeated values can be less than getaddrinfo_query_count
+ // + gethostbyname_query_count in case of event rate-limiting.
+ repeated int32 latencies_ms = 4;
+
+ // The total number of getaddrinfo queries.
+ // Since version 4.
+ optional int64 getaddrinfo_query_count = 5;
+
+ // The total number of gethostbyname queries.
+ // Since version 4.
+ optional int64 gethostbyname_query_count = 6;
+
+ // The total number of getaddrinfo errors.
+ // Since version 4.
+ optional int64 getaddrinfo_error_count = 7;
+
+ // The total number of gethostbyname errors.
+ // Since version 4.
+ optional int64 gethostbyname_error_count = 8;
+
+ // Counts of all errors returned by getaddrinfo.
+ // The Pair key field is the getaddrinfo error value.
+ // The value field is the count for that return value.
+ // Since version 4
+ repeated Pair getaddrinfo_errors = 9;
+
+ // Counts of all errors returned by gethostbyname.
+ // The Pair key field is the gethostbyname errno value.
+ // the Pair value field is the count for that errno code.
+ // Since version 4
+ repeated Pair gethostbyname_errors = 10;
+
+
+ // Deprecated fields
+
// The id of the network on which the DNS lookups took place.
- optional NetworkId network_id = 1;
+ // Deprecated since version 3.
+ optional NetworkId network_id = 1 [deprecated = true];
// The types of the DNS lookups, as defined in android.net.metrics.DnsEvent.
- repeated int32 event_types = 2;
+ // Deprecated since version 3.
+ repeated int32 event_types = 2 [deprecated = true];
// The return values of the DNS resolver for each DNS lookups.
- repeated int32 return_codes = 3;
-
- // The time it took for each DNS lookups to complete.
- repeated int32 latencies_ms = 4;
+ // Deprecated since version 3.
+ repeated int32 return_codes = 3 [deprecated = true];
};
// Represents a collections of DNS lookup latencies and counters for a
// particular combination of DNS query type and return code.
// Since version 2.
+// Next tag: 7.
message DNSLatencies {
// The type of the DNS lookups, as defined in android.net.metrics.DnsEvent.
// Acts as a key for a set of DNS query results.
@@ -203,6 +283,7 @@
// state transition or a response packet parsing error.
// This message is associated to android.net.metrics.DhcpClientEvent and
// android.net.metrics.DhcpErrorEvent.
+// Next tag: 5
message DHCPEvent {
// The interface name (wlan, rmnet, lo, ...) on which the event happened.
// Deprecated since version 2, to be replaced by link_layer field.
@@ -255,7 +336,7 @@
// Represents Router Advertisement listening statistics for an interface with
// Android Packet Filter enabled.
// Since version 1.
-// Next tag: 12
+// Next tag: 15
message ApfStatistics {
// The time interval in milliseconds these stastistics cover.
optional int64 duration_ms = 1;
@@ -288,12 +369,28 @@
// The total number of APF program updates triggered when disabling the
// multicast filter. Since version 3.
+ // Since version 4.
optional int32 program_updates_allowing_multicast = 11;
+
+ // The total number of packets processed by the APF interpreter.
+ // Since version 4.
+ optional int32 total_packet_processed = 12;
+
+ // The total number of packets dropped by the APF interpreter.
+ // Since version 4.
+ optional int32 total_packet_dropped = 13;
+
+ // List of hardware counters collected by the APF interpreter.
+ // The Pair key is the counter id, defined in android.net.metrics.ApfStats.
+ // The Pair value is the counter value.
+ // Since version 4.
+ repeated Pair hardware_counters = 14;
}
// Represents the reception of a Router Advertisement packet for an interface
// with Android Packet Filter enabled.
// Since version 1.
+// Next tag: 7.
message RaEvent {
// All lifetime values are expressed in seconds. The default value for an
// option lifetime that was not present in the RA option list is -1.
@@ -322,6 +419,7 @@
// Represents an IP provisioning event in IpManager and how long the
// provisioning action took.
// This message is associated to android.net.metrics.IpManagerEvent.
+// Next tag: 4.
message IpProvisioningEvent {
// The interface name (wlan, rmnet, lo, ...) on which the probe was sent.
// Deprecated since version 2, to be replaced by link_layer field.
@@ -335,8 +433,48 @@
optional int32 latency_ms = 3;
}
+// Represents statistics from a single android Network.
+// Since version 4. Replace NetworkEvent.
+// Next tag: 9.
+message NetworkStats {
+
+ // Duration of this Network lifecycle in milliseconds.
+ optional int64 duration_ms = 1;
+
+ // Information about IP support of this network.
+ optional DefaultNetworkEvent.IPSupport ip_support = 2;
+
+ // True if the network was validated at least once.
+ optional bool ever_validated = 3;
+
+ // True if a captive portal was found at least once on this network.
+ optional bool portal_found = 4;
+
+ // Total number of times no connectivity was reported for this network.
+ optional int32 no_connectivity_reports = 5;
+
+ // Total number of validation attempts.
+ optional int32 validation_attempts = 6;
+
+ // Results from all validation attempts.
+ // The Pair key is the result:
+ // 0 -> unvalidated
+ // 1 -> validated
+ // 2 -> captive portal
+ // The Pair value is the duration of the validation attempts in milliseconds.
+ repeated Pair validation_events = 7;
+
+ // Time series of validation states in time order.
+ // The Pair key is the state:
+ // 0 -> unvalidated
+ // 1 -> validated
+ // 2 -> captive portal,
+ // The Pair value is the duration of that state in milliseconds.
+ repeated Pair validation_states = 8;
+}
+
// Represents one of the IP connectivity event defined in this file.
-// Next tag: 19
+// Next tag: 20
message IpConnectivityEvent {
// Time in ms when the event was recorded.
optional int64 time_ms = 1;
@@ -370,14 +508,13 @@
oneof event {
// An event about the system default network.
- // The link_layer field is not relevant for this event and set to NONE.
DefaultNetworkEvent default_network_event = 2;
// An IP reachability probe event.
IpReachabilityEvent ip_reachability_event = 3;
// A network lifecycle event.
- NetworkEvent network_event = 4;
+ NetworkEvent network_event = 4 [deprecated = true];
// A batch of DNS lookups.
// Deprecated in the nyc-mr2 release since version 2,and replaced by
@@ -407,10 +544,14 @@
// An RA packet reception event.
RaEvent ra_event = 11;
+
+ // Network statistics.
+ NetworkStats network_stats = 19;
};
};
// The information about IP connectivity events.
+// Next tag: 4.
message IpConnectivityLog {
// An array of IP connectivity events.
repeated IpConnectivityEvent events = 1;
@@ -424,5 +565,6 @@
// nyc-mr1: not populated, implicitly 1.
// nyc-mr2: 2.
// oc: 3.
+ // oc-dr1: 4. (sailfish, marlin, walleye, taimen)
optional int32 version = 3;
};
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 8292178..5319086 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -138,6 +138,18 @@
REASON_TIMEOUT = 19;
}
+ // Subtypes of camera events for ACTION_CAMERA_EVENT
+ enum CameraEvent {
+ // A back-facing camera was used
+ CAMERA_BACK_USED = 0;
+
+ // A front-facing camera was used
+ CAMERA_FRONT_USED = 1;
+
+ // An external camera was used
+ CAMERA_EXTERNAL_USED = 2;
+ }
+
// Known visual elements: views or controls.
enum View {
// Unknown view
@@ -4196,6 +4208,12 @@
// OS: O DR
DIALOG_BLUETOOTH_PAIRED_DEVICE_FORGET = 1031;
+ // An event from the camera service
+ // CATEGORY: OTHER
+ // SUBTYPE: CameraEvent
+ // OS: O DR
+ ACTION_CAMERA_EVENT = 1032;
+
// ---- End O-DR1 Constants, all O-DR1 constants go above this line ----
// ACTION: Settings > Network & Internet > Mobile network > Mobile data
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 8b15d50..67ee185 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -163,7 +163,8 @@
@Nullable String filterText, @NonNull String packageName,
@NonNull AutoFillUiCallback callback) {
if (sDebug) {
- Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + filterText);
+ final int size = filterText == null ? 0 : filterText.length();
+ Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + size + " chars");
}
final LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI))
.setPackageName(packageName)
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 51a239f..24f3b33 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -204,7 +204,10 @@
return;
}
if (count <= 0) {
- if (sDebug) Slog.d(TAG, "No dataset matches filter: " + mFilterText);
+ if (sDebug) {
+ final int size = mFilterText == null ? 0 : mFilterText.length();
+ Slog.d(TAG, "No dataset matches filter with " + size + " chars");
+ }
mCallback.requestHideFillUi();
} else {
if (updateContentSize()) {
diff --git a/services/backup/java/com/android/server/backup/BackupPasswordManager.java b/services/backup/java/com/android/server/backup/BackupPasswordManager.java
new file mode 100644
index 0000000..ee7651b
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/BackupPasswordManager.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2017 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.backup;
+
+import android.content.Context;
+import android.util.Slog;
+
+import com.android.server.backup.utils.DataStreamFileCodec;
+import com.android.server.backup.utils.DataStreamCodec;
+import com.android.server.backup.utils.PasswordUtils;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.security.SecureRandom;
+
+/**
+ * Manages persisting and verifying backup passwords.
+ *
+ * <p>Does not persist the password itself, but persists a PBKDF2 hash with a randomly chosen (also
+ * persisted) salt. Validation is performed by running the challenge text through the same
+ * PBKDF2 cycle with the persisted salt, and checking the hashes match.
+ *
+ * @see PasswordUtils for the hashing algorithm.
+ */
+public final class BackupPasswordManager {
+ private static final String TAG = "BackupPasswordManager";
+ private static final boolean DEBUG = false;
+
+ private static final int BACKUP_PW_FILE_VERSION = 2;
+ private static final int DEFAULT_PW_FILE_VERSION = 1;
+
+ private static final String PASSWORD_VERSION_FILE_NAME = "pwversion";
+ private static final String PASSWORD_HASH_FILE_NAME = "pwhash";
+
+ // See https://android-developers.googleblog.com/2013/12/changes-to-secretkeyfactory-api-in.html
+ public static final String PBKDF_CURRENT = "PBKDF2WithHmacSHA1";
+ public static final String PBKDF_FALLBACK = "PBKDF2WithHmacSHA1And8bit";
+
+ private final SecureRandom mRng;
+ private final Context mContext;
+ private final File mBaseStateDir;
+
+ private String mPasswordHash;
+ private int mPasswordVersion;
+ private byte[] mPasswordSalt;
+
+ /**
+ * Creates an instance enforcing permissions using the {@code context} and persisting password
+ * data within the {@code baseStateDir}.
+ *
+ * @param context The context, for enforcing permissions around setting the password.
+ * @param baseStateDir A directory within which to persist password data.
+ * @param secureRandom Random number generator with which to generate password salts.
+ */
+ BackupPasswordManager(Context context, File baseStateDir, SecureRandom secureRandom) {
+ mContext = context;
+ mRng = secureRandom;
+ mBaseStateDir = baseStateDir;
+ loadStateFromFilesystem();
+ }
+
+ /**
+ * Returns {@code true} if a password for backup is set.
+ *
+ * @throws SecurityException If caller does not have {@link android.Manifest.permission#BACKUP}
+ * permission.
+ */
+ boolean hasBackupPassword() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "hasBackupPassword");
+ return mPasswordHash != null && mPasswordHash.length() > 0;
+ }
+
+ /**
+ * Returns {@code true} if {@code password} matches the persisted password.
+ *
+ * @throws SecurityException If caller does not have {@link android.Manifest.permission#BACKUP}
+ * permission.
+ */
+ boolean backupPasswordMatches(String password) {
+ if (hasBackupPassword() && !passwordMatchesSaved(password)) {
+ if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Sets the new password, given a correct current password.
+ *
+ * @throws SecurityException If caller does not have {@link android.Manifest.permission#BACKUP}
+ * permission.
+ * @return {@code true} if has permission to set the password, {@code currentPassword}
+ * matches the currently persisted password, and is able to persist {@code newPassword}.
+ */
+ boolean setBackupPassword(String currentPassword, String newPassword) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "setBackupPassword");
+
+ if (!passwordMatchesSaved(currentPassword)) {
+ return false;
+ }
+
+ // Snap up to latest password file version.
+ try {
+ getPasswordVersionFileCodec().serialize(BACKUP_PW_FILE_VERSION);
+ mPasswordVersion = BACKUP_PW_FILE_VERSION;
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to write backup pw version; password not changed");
+ return false;
+ }
+
+ if (newPassword == null || newPassword.isEmpty()) {
+ return clearPassword();
+ }
+
+ try {
+ byte[] salt = randomSalt();
+ String newPwHash = PasswordUtils.buildPasswordHash(
+ PBKDF_CURRENT, newPassword, salt, PasswordUtils.PBKDF2_HASH_ROUNDS);
+
+ getPasswordHashFileCodec().serialize(new BackupPasswordHash(newPwHash, salt));
+ mPasswordHash = newPwHash;
+ mPasswordSalt = salt;
+ return true;
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to set backup password");
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if should try salting using the older PBKDF algorithm.
+ *
+ * <p>This is {@code true} for v1 files.
+ */
+ private boolean usePbkdf2Fallback() {
+ return mPasswordVersion < BACKUP_PW_FILE_VERSION;
+ }
+
+ /**
+ * Deletes the current backup password.
+ *
+ * @return {@code true} if successful.
+ */
+ private boolean clearPassword() {
+ File passwordHashFile = getPasswordHashFile();
+ if (passwordHashFile.exists() && !passwordHashFile.delete()) {
+ Slog.e(TAG, "Unable to clear backup password");
+ return false;
+ }
+
+ mPasswordHash = null;
+ mPasswordSalt = null;
+ return true;
+ }
+
+ /**
+ * Sets the password hash, salt, and version in the object from what has been persisted to the
+ * filesystem.
+ */
+ private void loadStateFromFilesystem() {
+ try {
+ mPasswordVersion = getPasswordVersionFileCodec().deserialize();
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read backup pw version");
+ mPasswordVersion = DEFAULT_PW_FILE_VERSION;
+ }
+
+ try {
+ BackupPasswordHash hash = getPasswordHashFileCodec().deserialize();
+ mPasswordHash = hash.hash;
+ mPasswordSalt = hash.salt;
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read saved backup pw hash");
+ }
+ }
+
+ /**
+ * Whether the candidate password matches the current password. If the persisted password is an
+ * older version, attempts hashing using the older algorithm.
+ *
+ * @param candidatePassword The password to try.
+ * @return {@code true} if the passwords match.
+ */
+ private boolean passwordMatchesSaved(String candidatePassword) {
+ return passwordMatchesSaved(PBKDF_CURRENT, candidatePassword)
+ || (usePbkdf2Fallback() && passwordMatchesSaved(PBKDF_FALLBACK, candidatePassword));
+ }
+
+ /**
+ * Returns {@code true} if the candidate password is correct.
+ *
+ * @param algorithm The algorithm used to hash passwords.
+ * @param candidatePassword The candidate password to compare to the current password.
+ * @return {@code true} if the candidate password matched the saved password.
+ */
+ private boolean passwordMatchesSaved(String algorithm, String candidatePassword) {
+ if (mPasswordHash == null) {
+ return candidatePassword == null || candidatePassword.equals("");
+ } else if (candidatePassword == null || candidatePassword.length() == 0) {
+ // The current password is not zero-length, but the candidate password is.
+ return false;
+ } else {
+ String candidatePasswordHash = PasswordUtils.buildPasswordHash(
+ algorithm, candidatePassword, mPasswordSalt, PasswordUtils.PBKDF2_HASH_ROUNDS);
+ return mPasswordHash.equalsIgnoreCase(candidatePasswordHash);
+ }
+ }
+
+ private byte[] randomSalt() {
+ int bitsPerByte = 8;
+ byte[] array = new byte[PasswordUtils.PBKDF2_SALT_SIZE / bitsPerByte];
+ mRng.nextBytes(array);
+ return array;
+ }
+
+ private DataStreamFileCodec<Integer> getPasswordVersionFileCodec() {
+ return new DataStreamFileCodec<>(
+ new File(mBaseStateDir, PASSWORD_VERSION_FILE_NAME),
+ new PasswordVersionFileCodec());
+ }
+
+ private DataStreamFileCodec<BackupPasswordHash> getPasswordHashFileCodec() {
+ return new DataStreamFileCodec<>(getPasswordHashFile(), new PasswordHashFileCodec());
+ }
+
+ private File getPasswordHashFile() {
+ return new File(mBaseStateDir, PASSWORD_HASH_FILE_NAME);
+ }
+
+ /**
+ * Container class for a PBKDF hash and the salt used to create the hash.
+ */
+ private static final class BackupPasswordHash {
+ public String hash;
+ public byte[] salt;
+
+ BackupPasswordHash(String hash, byte[] salt) {
+ this.hash = hash;
+ this.salt = salt;
+ }
+ }
+
+ /**
+ * The password version file contains a single 32-bit integer.
+ */
+ private static final class PasswordVersionFileCodec implements
+ DataStreamCodec<Integer> {
+ @Override
+ public void serialize(Integer integer, DataOutputStream dataOutputStream)
+ throws IOException {
+ dataOutputStream.write(integer);
+ }
+
+ @Override
+ public Integer deserialize(DataInputStream dataInputStream) throws IOException {
+ return dataInputStream.readInt();
+ }
+ }
+
+ /**
+ * The passwords hash file contains
+ *
+ * <ul>
+ * <li>A 32-bit integer representing the number of bytes in the salt;
+ * <li>The salt bytes;
+ * <li>A UTF-8 string of the hash.
+ * </ul>
+ */
+ private static final class PasswordHashFileCodec implements
+ DataStreamCodec<BackupPasswordHash> {
+ @Override
+ public void serialize(BackupPasswordHash backupPasswordHash,
+ DataOutputStream dataOutputStream) throws IOException {
+ dataOutputStream.writeInt(backupPasswordHash.salt.length);
+ dataOutputStream.write(backupPasswordHash.salt);
+ dataOutputStream.writeUTF(backupPasswordHash.hash);
+ }
+
+ @Override
+ public BackupPasswordHash deserialize(
+ DataInputStream dataInputStream) throws IOException {
+ int saltLen = dataInputStream.readInt();
+ byte[] salt = new byte[saltLen];
+ dataInputStream.readFully(salt);
+ String hash = dataInputStream.readUTF();
+ return new BackupPasswordHash(hash, salt);
+ }
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/DataChangedJournal.java b/services/backup/java/com/android/server/backup/DataChangedJournal.java
new file mode 100644
index 0000000..9360c85
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/DataChangedJournal.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2017 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.backup;
+
+import android.annotation.Nullable;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+
+/**
+ * A journal of packages that have indicated that their data has changed (and therefore should be
+ * backed up in the next scheduled K/V backup pass).
+ *
+ * <p>This information is persisted to the filesystem so that it is not lost in the event of a
+ * reboot.
+ */
+public final class DataChangedJournal {
+ private static final String FILE_NAME_PREFIX = "journal";
+
+ /**
+ * Journals tend to be on the order of a few kilobytes, hence setting the buffer size to 8kb.
+ */
+ private static final int BUFFER_SIZE_BYTES = 8 * 1024;
+
+ private final File mFile;
+
+ /**
+ * Constructs an instance that reads from and writes to the given file.
+ */
+ DataChangedJournal(File file) {
+ mFile = file;
+ }
+
+ /**
+ * Adds the given package to the journal.
+ *
+ * @param packageName The name of the package whose data has changed.
+ * @throws IOException if there is an IO error writing to the journal file.
+ */
+ public void addPackage(String packageName) throws IOException {
+ try (RandomAccessFile out = new RandomAccessFile(mFile, "rws")) {
+ out.seek(out.length());
+ out.writeUTF(packageName);
+ }
+ }
+
+ /**
+ * Invokes {@link Consumer#accept(String)} with every package name in the journal file.
+ *
+ * @param consumer The callback.
+ * @throws IOException If there is an IO error reading from the file.
+ */
+ public void forEach(Consumer consumer) throws IOException {
+ try (
+ BufferedInputStream bufferedInputStream = new BufferedInputStream(
+ new FileInputStream(mFile), BUFFER_SIZE_BYTES);
+ DataInputStream dataInputStream = new DataInputStream(bufferedInputStream)
+ ) {
+ while (dataInputStream.available() > 0) {
+ String packageName = dataInputStream.readUTF();
+ consumer.accept(packageName);
+ }
+ }
+ }
+
+ /**
+ * Deletes the journal from the filesystem.
+ *
+ * @return {@code true} if successfully deleted journal.
+ */
+ public boolean delete() {
+ return mFile.delete();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (object instanceof DataChangedJournal) {
+ DataChangedJournal that = (DataChangedJournal) object;
+ try {
+ return this.mFile.getCanonicalPath().equals(that.mFile.getCanonicalPath());
+ } catch (IOException exception) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return mFile.toString();
+ }
+
+ /**
+ * Consumer for iterating over package names in the journal.
+ */
+ @FunctionalInterface
+ public interface Consumer {
+ void accept(String packageName);
+ }
+
+ /**
+ * Creates a new journal with a random file name in the given journal directory.
+ *
+ * @param journalDirectory The directory where journals are kept.
+ * @return The journal.
+ * @throws IOException if there is an IO error creating the file.
+ */
+ static DataChangedJournal newJournal(File journalDirectory) throws IOException {
+ return new DataChangedJournal(
+ File.createTempFile(FILE_NAME_PREFIX, null, journalDirectory));
+ }
+
+ /**
+ * Returns a list of journals in the given journal directory.
+ */
+ static ArrayList<DataChangedJournal> listJournals(File journalDirectory) {
+ ArrayList<DataChangedJournal> journals = new ArrayList<>();
+ for (File file : journalDirectory.listFiles()) {
+ journals.add(new DataChangedJournal(file));
+ }
+ return journals;
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 7e28f61..d118917 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -32,6 +32,7 @@
import static com.android.server.backup.internal.BackupHandler.MSG_RUN_RESTORE;
import static com.android.server.backup.internal.BackupHandler.MSG_SCHEDULE_BACKUP_PACKAGE;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AppGlobals;
@@ -117,13 +118,12 @@
import com.android.server.backup.utils.AppBackupUtils;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import com.android.server.backup.utils.BackupObserverUtils;
-import com.android.server.backup.utils.PasswordUtils;
+import com.android.server.backup.utils.SparseArrayUtils;
import com.android.server.power.BatterySaverPolicy.ServiceType;
-import libcore.io.IoUtils;
+import com.google.android.collect.Sets;
import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -135,7 +135,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.security.SecureRandom;
@@ -169,10 +168,6 @@
// with U+FF00 or higher for system use).
public static final String KEY_WIDGET_STATE = "\uffed\uffedwidget";
- // Historical and current algorithm names
- public static final String PBKDF_CURRENT = "PBKDF2WithHmacSHA1";
- public static final String PBKDF_FALLBACK = "PBKDF2WithHmacSHA1And8bit";
-
// Name and current contents version of the full-backup manifest file
//
// Manifest version history:
@@ -190,7 +185,6 @@
// 5 : added support for key-value packages
public static final int BACKUP_FILE_VERSION = 5;
public static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
- private static final int BACKUP_PW_FILE_VERSION = 2;
public static final String BACKUP_METADATA_FILENAME = "_meta";
public static final int BACKUP_METADATA_VERSION = 1;
public static final int BACKUP_WIDGET_METADATA_TOKEN = 0x01FFED01;
@@ -283,6 +277,8 @@
private final Object mClearDataLock = new Object();
private volatile boolean mClearingData;
+ private final BackupPasswordManager mBackupPasswordManager;
+
@GuardedBy("mPendingRestores")
private boolean mIsRestoreInProgress;
@GuardedBy("mPendingRestores")
@@ -482,11 +478,11 @@
mDataDir = dataDir;
}
- public File getJournal() {
+ public DataChangedJournal getJournal() {
return mJournal;
}
- public void setJournal(File journal) {
+ public void setJournal(@Nullable DataChangedJournal journal) {
mJournal = journal;
}
@@ -630,20 +626,9 @@
private File mBaseStateDir;
private File mDataDir;
private File mJournalDir;
- private File mJournal;
+ @Nullable private DataChangedJournal mJournal;
- // Backup password, if any, and the file where it's saved. What is stored is not the
- // password text itself; it's the result of a PBKDF2 hash with a randomly chosen (but
- // persisted) salt. Validation is performed by running the challenge text through the
- // same PBKDF2 cycle with the persisted salt; if the resulting derived key string matches
- // the saved hash string, then the challenge text matches the originally supplied
- // password text.
private final SecureRandom mRng = new SecureRandom();
- private String mPasswordHash;
- private File mPasswordHashFile;
- private int mPasswordVersion;
- private File mPasswordVersionFile;
- private byte[] mPasswordSalt;
// Keep a log of all the apps we've ever backed up, and what the
// dataset tokens are for both the current backup dataset and
@@ -745,52 +730,7 @@
// This dir on /cache is managed directly in init.rc
mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage");
- mPasswordVersion = 1; // unless we hear otherwise
- mPasswordVersionFile = new File(mBaseStateDir, "pwversion");
- if (mPasswordVersionFile.exists()) {
- FileInputStream fin = null;
- DataInputStream in = null;
- try {
- fin = new FileInputStream(mPasswordVersionFile);
- in = new DataInputStream(fin);
- mPasswordVersion = in.readInt();
- } catch (IOException e) {
- Slog.e(TAG, "Unable to read backup pw version");
- } finally {
- try {
- if (in != null) in.close();
- if (fin != null) fin.close();
- } catch (IOException e) {
- Slog.w(TAG, "Error closing pw version files");
- }
- }
- }
-
- mPasswordHashFile = new File(mBaseStateDir, "pwhash");
- if (mPasswordHashFile.exists()) {
- FileInputStream fin = null;
- DataInputStream in = null;
- try {
- fin = new FileInputStream(mPasswordHashFile);
- in = new DataInputStream(new BufferedInputStream(fin));
- // integer length of the salt array, followed by the salt,
- // then the hex pw hash string
- int saltLen = in.readInt();
- byte[] salt = new byte[saltLen];
- in.readFully(salt);
- mPasswordHash = in.readUTF();
- mPasswordSalt = salt;
- } catch (IOException e) {
- Slog.e(TAG, "Unable to read saved backup pw hash");
- } finally {
- try {
- if (in != null) in.close();
- if (fin != null) fin.close();
- } catch (IOException e) {
- Slog.w(TAG, "Unable to close streams");
- }
- }
- }
+ mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
// Alarm receivers for scheduled backups & initialization operations
mRunBackupReceiver = new RunBackupReceiver(this);
@@ -859,8 +799,7 @@
// Remember our ancestral dataset
mTokenFile = new File(mBaseStateDir, "ancestral");
- try {
- RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
+ try (RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r")) {
int version = tf.readInt();
if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
mAncestralToken = tf.readLong();
@@ -875,7 +814,6 @@
}
}
}
- tf.close();
} catch (FileNotFoundException fnf) {
// Probably innocuous
Slog.v(TAG, "No ancestral data");
@@ -899,13 +837,8 @@
// If there are previous contents, parse them out then start a new
// file to continue the recordkeeping.
if (mEverStored.exists()) {
- RandomAccessFile temp = null;
- RandomAccessFile in = null;
-
- try {
- temp = new RandomAccessFile(tempProcessedFile, "rws");
- in = new RandomAccessFile(mEverStored, "r");
-
+ try (RandomAccessFile temp = new RandomAccessFile(tempProcessedFile, "rws");
+ RandomAccessFile in = new RandomAccessFile(mEverStored, "r")) {
// Loop until we hit EOF
while (true) {
String pkg = in.readUTF();
@@ -929,15 +862,6 @@
}
} catch (IOException e) {
Slog.e(TAG, "Error in processed file", e);
- } finally {
- try {
- if (temp != null) temp.close();
- } catch (IOException e) {
- }
- try {
- if (in != null) in.close();
- } catch (IOException e) {
- }
}
}
@@ -968,14 +892,9 @@
PackageManagerBackupAgent.getStorableApplications(mPackageManager);
if (mFullBackupScheduleFile.exists()) {
- FileInputStream fstream = null;
- BufferedInputStream bufStream = null;
- DataInputStream in = null;
- try {
- fstream = new FileInputStream(mFullBackupScheduleFile);
- bufStream = new BufferedInputStream(fstream);
- in = new DataInputStream(bufStream);
-
+ try (FileInputStream fstream = new FileInputStream(mFullBackupScheduleFile);
+ BufferedInputStream bufStream = new BufferedInputStream(fstream);
+ DataInputStream in = new DataInputStream(bufStream)) {
int version = in.readInt();
if (version != SCHEDULE_FILE_VERSION) {
Slog.e(TAG, "Unknown backup schedule version " + version);
@@ -1036,10 +955,6 @@
Slog.e(TAG, "Unable to read backup schedule", e);
mFullBackupScheduleFile.delete();
schedule = null;
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(bufStream);
- IoUtils.closeQuietly(fstream);
}
}
@@ -1105,35 +1020,17 @@
}
private void parseLeftoverJournals() {
- for (File f : mJournalDir.listFiles()) {
- if (mJournal == null || f.compareTo(mJournal) != 0) {
- // This isn't the current journal, so it must be a leftover. Read
- // out the package names mentioned there and schedule them for
- // backup.
- DataInputStream in = null;
+ ArrayList<DataChangedJournal> journals = DataChangedJournal.listJournals(mJournalDir);
+ for (DataChangedJournal journal : journals) {
+ if (!journal.equals(mJournal)) {
try {
- Slog.i(TAG, "Found stale backup journal, scheduling");
- // Journals will tend to be on the order of a few kilobytes(around 4k), hence,
- // setting the buffer size to 8192.
- InputStream bufferedInputStream = new BufferedInputStream(
- new FileInputStream(f), 8192);
- in = new DataInputStream(bufferedInputStream);
- while (true) {
- String packageName = in.readUTF();
+ journal.forEach(packageName -> {
+ Slog.i(TAG, "Found stale backup journal, scheduling");
if (MORE_DEBUG) Slog.i(TAG, " " + packageName);
dataChangedImpl(packageName);
- }
- } catch (EOFException e) {
- // no more data; we're done
- } catch (Exception e) {
- Slog.e(TAG, "Can't read " + f, e);
- } finally {
- // close/delete the file
- try {
- if (in != null) in.close();
- } catch (IOException e) {
- }
- f.delete();
+ });
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't read " + journal, e);
}
}
}
@@ -1146,128 +1043,18 @@
return array;
}
- private boolean passwordMatchesSaved(String algorithm, String candidatePw, int rounds) {
- if (mPasswordHash == null) {
- // no current password case -- require that 'currentPw' be null or empty
- if (candidatePw == null || "".equals(candidatePw)) {
- return true;
- } // else the non-empty candidate does not match the empty stored pw
- } else {
- // hash the stated current pw and compare to the stored one
- if (candidatePw != null && candidatePw.length() > 0) {
- String currentPwHash = PasswordUtils.buildPasswordHash(algorithm, candidatePw,
- mPasswordSalt,
- rounds);
- if (mPasswordHash.equalsIgnoreCase(currentPwHash)) {
- // candidate hash matches the stored hash -- the password matches
- return true;
- }
- } // else the stored pw is nonempty but the candidate is empty; no match
- }
- return false;
- }
-
@Override
public boolean setBackupPassword(String currentPw, String newPw) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "setBackupPassword");
-
- // When processing v1 passwords we may need to try two different PBKDF2 checksum regimes
- final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
-
- // If the supplied pw doesn't hash to the the saved one, fail. The password
- // might be caught in the legacy crypto mismatch; verify that too.
- if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PasswordUtils.PBKDF2_HASH_ROUNDS)
- && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
- currentPw, PasswordUtils.PBKDF2_HASH_ROUNDS))) {
- return false;
- }
-
- // Snap up to current on the pw file version
- mPasswordVersion = BACKUP_PW_FILE_VERSION;
- FileOutputStream pwFout = null;
- DataOutputStream pwOut = null;
- try {
- pwFout = new FileOutputStream(mPasswordVersionFile);
- pwOut = new DataOutputStream(pwFout);
- pwOut.writeInt(mPasswordVersion);
- } catch (IOException e) {
- Slog.e(TAG, "Unable to write backup pw version; password not changed");
- return false;
- } finally {
- try {
- if (pwOut != null) pwOut.close();
- if (pwFout != null) pwFout.close();
- } catch (IOException e) {
- Slog.w(TAG, "Unable to close pw version record");
- }
- }
-
- // Clearing the password is okay
- if (newPw == null || newPw.isEmpty()) {
- if (mPasswordHashFile.exists()) {
- if (!mPasswordHashFile.delete()) {
- // Unable to delete the old pw file, so fail
- Slog.e(TAG, "Unable to clear backup password");
- return false;
- }
- }
- mPasswordHash = null;
- mPasswordSalt = null;
- return true;
- }
-
- try {
- // Okay, build the hash of the new backup password
- byte[] salt = randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);
- String newPwHash = PasswordUtils.buildPasswordHash(PBKDF_CURRENT, newPw, salt,
- PasswordUtils.PBKDF2_HASH_ROUNDS);
-
- OutputStream pwf = null, buffer = null;
- DataOutputStream out = null;
- try {
- pwf = new FileOutputStream(mPasswordHashFile);
- buffer = new BufferedOutputStream(pwf);
- out = new DataOutputStream(buffer);
- // integer length of the salt array, followed by the salt,
- // then the hex pw hash string
- out.writeInt(salt.length);
- out.write(salt);
- out.writeUTF(newPwHash);
- out.flush();
- mPasswordHash = newPwHash;
- mPasswordSalt = salt;
- return true;
- } finally {
- if (out != null) out.close();
- if (buffer != null) buffer.close();
- if (pwf != null) pwf.close();
- }
- } catch (IOException e) {
- Slog.e(TAG, "Unable to set backup password");
- }
- return false;
+ return mBackupPasswordManager.setBackupPassword(currentPw, newPw);
}
@Override
public boolean hasBackupPassword() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
- "hasBackupPassword");
-
- return mPasswordHash != null && mPasswordHash.length() > 0;
+ return mBackupPasswordManager.hasBackupPassword();
}
public boolean backupPasswordMatches(String currentPw) {
- if (hasBackupPassword()) {
- final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
- if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PasswordUtils.PBKDF2_HASH_ROUNDS)
- && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
- currentPw, PasswordUtils.PBKDF2_HASH_ROUNDS))) {
- if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
- return false;
- }
- }
- return true;
+ return mBackupPasswordManager.backupPasswordMatches(currentPw);
}
// Maintain persistent state around whether need to do an initialize operation.
@@ -1628,18 +1415,11 @@
synchronized (mEverStoredApps) {
if (!mEverStoredApps.add(packageName)) return;
- RandomAccessFile out = null;
- try {
- out = new RandomAccessFile(mEverStored, "rws");
+ try (RandomAccessFile out = new RandomAccessFile(mEverStored, "rws")) {
out.seek(out.length());
out.writeUTF(packageName);
} catch (IOException e) {
Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
- } finally {
- try {
- if (out != null) out.close();
- } catch (IOException e) {
- }
}
}
}
@@ -1654,16 +1434,13 @@
// we'll recognize on initialization time that the package no longer
// exists and fix it up then.
File tempKnownFile = new File(mBaseStateDir, "processed.new");
- RandomAccessFile known = null;
- try {
- known = new RandomAccessFile(tempKnownFile, "rws");
+ try (RandomAccessFile known = new RandomAccessFile(tempKnownFile, "rws")) {
mEverStoredApps.remove(packageName);
for (String s : mEverStoredApps) {
known.writeUTF(s);
if (MORE_DEBUG) Slog.v(TAG, " " + s);
}
known.close();
- known = null;
if (!tempKnownFile.renameTo(mEverStored)) {
throw new IOException("Can't rename " + tempKnownFile + " to " + mEverStored);
}
@@ -1676,11 +1453,6 @@
mEverStoredApps.clear();
tempKnownFile.delete();
mEverStored.delete();
- } finally {
- try {
- if (known != null) known.close();
- } catch (IOException e) {
- }
}
}
}
@@ -1689,9 +1461,7 @@
// as the set of packages with data [supposedly] available in the
// ancestral dataset.
public void writeRestoreTokens() {
- try {
- RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
-
+ try (RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd")) {
// First, the version number of this record, for futureproofing
af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
@@ -1710,7 +1480,6 @@
if (MORE_DEBUG) Slog.v(TAG, " " + pkgName);
}
}
- af.close();
} catch (IOException e) {
Slog.w(TAG, "Unable to write token file:", e);
}
@@ -2489,38 +2258,22 @@
}
// a caller with full permission can ask to back up any participating app
- HashSet<String> targets = new HashSet<>();
if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) {
- targets.add(PACKAGE_MANAGER_SENTINEL);
+ return Sets.newHashSet(PACKAGE_MANAGER_SENTINEL);
} else {
synchronized (mBackupParticipants) {
- int N = mBackupParticipants.size();
- for (int i = 0; i < N; i++) {
- HashSet<String> s = mBackupParticipants.valueAt(i);
- if (s != null) {
- targets.addAll(s);
- }
- }
+ return SparseArrayUtils.union(mBackupParticipants);
}
}
- return targets;
}
private void writeToJournalLocked(String str) {
- RandomAccessFile out = null;
try {
- if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir);
- out = new RandomAccessFile(mJournal, "rws");
- out.seek(out.length());
- out.writeUTF(str);
+ if (mJournal == null) mJournal = DataChangedJournal.newJournal(mJournalDir);
+ mJournal.addPackage(str);
} catch (IOException e) {
Slog.e(TAG, "Can't write " + str + " to backup journal", e);
mJournal = null;
- } finally {
- try {
- if (out != null) out.close();
- } catch (IOException e) {
- }
}
}
@@ -2595,14 +2348,7 @@
// a caller with full permission can ask to back up any participating app
// !!! TODO: allow data-clear of ANY app?
if (MORE_DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
- apps = new HashSet<>();
- int N = mBackupParticipants.size();
- for (int i = 0; i < N; i++) {
- HashSet<String> s = mBackupParticipants.valueAt(i);
- if (s != null) {
- apps.addAll(s);
- }
- }
+ apps = SparseArrayUtils.union(mBackupParticipants);
}
// Is the given app an available participant?
@@ -2978,9 +2724,7 @@
File base = new File(Environment.getDataDirectory(), "backup");
File enableFile = new File(base, BACKUP_ENABLE_FILE);
File stage = new File(base, BACKUP_ENABLE_FILE + "-stage");
- FileOutputStream fout = null;
- try {
- fout = new FileOutputStream(stage);
+ try (FileOutputStream fout = new FileOutputStream(stage)) {
fout.write(enable ? 1 : 0);
fout.close();
stage.renameTo(enableFile);
@@ -2996,8 +2740,6 @@
Settings.Secure.BACKUP_ENABLED, null, userId);
enableFile.delete();
stage.delete();
- } finally {
- IoUtils.closeQuietly(fout);
}
}
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 007d930..804e92c 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -16,11 +16,11 @@
package com.android.server.backup.fullbackup;
+import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT;
import static com.android.server.backup.RefactoredBackupManagerService.BACKUP_FILE_HEADER_MAGIC;
import static com.android.server.backup.RefactoredBackupManagerService.BACKUP_FILE_VERSION;
import static com.android.server.backup.RefactoredBackupManagerService.DEBUG;
import static com.android.server.backup.RefactoredBackupManagerService.MORE_DEBUG;
-import static com.android.server.backup.RefactoredBackupManagerService.PBKDF_CURRENT;
import static com.android.server.backup.RefactoredBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
import static com.android.server.backup.RefactoredBackupManagerService.TAG;
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index edd3894..8f82300 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -36,6 +36,7 @@
import com.android.internal.backup.IBackupTransport;
import com.android.server.EventLogTags;
import com.android.server.backup.BackupRestoreTask;
+import com.android.server.backup.DataChangedJournal;
import com.android.server.backup.RefactoredBackupManagerService;
import com.android.server.backup.fullbackup.PerformAdbBackupTask;
import com.android.server.backup.fullbackup.PerformFullTransportBackupTask;
@@ -107,7 +108,7 @@
// snapshot the pending-backup set and work on that
ArrayList<BackupRequest> queue = new ArrayList<>();
- File oldJournal = backupManagerService.getJournal();
+ DataChangedJournal oldJournal = backupManagerService.getJournal();
synchronized (backupManagerService.getQueueLock()) {
// Do we have any work to do? Construct the work queue
// then release the synchronization lock to actually run
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index a996e2d..5d4fcf4 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -28,6 +28,7 @@
import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT;
import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP;
+import android.annotation.Nullable;
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
import android.app.backup.BackupDataInput;
@@ -57,6 +58,7 @@
import com.android.server.AppWidgetBackupBridge;
import com.android.server.EventLogTags;
import com.android.server.backup.BackupRestoreTask;
+import com.android.server.backup.DataChangedJournal;
import com.android.server.backup.KeyValueBackupJob;
import com.android.server.backup.PackageManagerBackupAgent;
import com.android.server.backup.RefactoredBackupManagerService;
@@ -114,7 +116,7 @@
ArrayList<BackupRequest> mQueue;
ArrayList<BackupRequest> mOriginalQueue;
File mStateDir;
- File mJournal;
+ @Nullable DataChangedJournal mJournal;
BackupState mCurrentState;
List<String> mPendingFullBackups;
IBackupObserver mObserver;
@@ -142,9 +144,9 @@
public PerformBackupTask(RefactoredBackupManagerService backupManagerService,
IBackupTransport transport, String dirName,
- ArrayList<BackupRequest> queue, File journal, IBackupObserver observer,
- IBackupManagerMonitor monitor, List<String> pendingFullBackups,
- boolean userInitiated, boolean nonIncremental) {
+ ArrayList<BackupRequest> queue, @Nullable DataChangedJournal journal,
+ IBackupObserver observer, IBackupManagerMonitor monitor,
+ List<String> pendingFullBackups, boolean userInitiated, boolean nonIncremental) {
this.backupManagerService = backupManagerService;
mTransport = transport;
mOriginalQueue = queue;
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index b1d6afc..62ae065 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -16,6 +16,8 @@
package com.android.server.backup.restore;
+import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT;
+import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK;
import static com.android.server.backup.RefactoredBackupManagerService.BACKUP_FILE_HEADER_MAGIC;
import static com.android.server.backup.RefactoredBackupManagerService.BACKUP_FILE_VERSION;
import static com.android.server.backup.RefactoredBackupManagerService.BACKUP_MANIFEST_FILENAME;
@@ -23,8 +25,6 @@
import static com.android.server.backup.RefactoredBackupManagerService.DEBUG;
import static com.android.server.backup.RefactoredBackupManagerService.MORE_DEBUG;
import static com.android.server.backup.RefactoredBackupManagerService.OP_TYPE_RESTORE_WAIT;
-import static com.android.server.backup.RefactoredBackupManagerService.PBKDF_CURRENT;
-import static com.android.server.backup.RefactoredBackupManagerService.PBKDF_FALLBACK;
import static com.android.server.backup.RefactoredBackupManagerService.SETTINGS_PACKAGE;
import static com.android.server.backup.RefactoredBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
import static com.android.server.backup.RefactoredBackupManagerService.TAG;
diff --git a/services/backup/java/com/android/server/backup/utils/DataStreamCodec.java b/services/backup/java/com/android/server/backup/utils/DataStreamCodec.java
new file mode 100644
index 0000000..b1e226d
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/utils/DataStreamCodec.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 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.backup.utils;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Implements how to serialize a {@code T} to a {@link DataOutputStream} and how to deserialize a
+ * {@code T} from a {@link DataInputStream}.
+ *
+ * @param <T> Type of object to be serialized / deserialized.
+ */
+public interface DataStreamCodec<T> {
+ /**
+ * Serializes {@code t} to {@code dataOutputStream}.
+ */
+ void serialize(T t, DataOutputStream dataOutputStream) throws IOException;
+
+ /**
+ * Deserializes {@code t} from {@code dataInputStream}.
+ */
+ T deserialize(DataInputStream dataInputStream) throws IOException;
+}
+
diff --git a/services/backup/java/com/android/server/backup/utils/DataStreamFileCodec.java b/services/backup/java/com/android/server/backup/utils/DataStreamFileCodec.java
new file mode 100644
index 0000000..7753b03
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/utils/DataStreamFileCodec.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 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.backup.utils;
+
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Provides an interface for serializing an object to a file and deserializing it back again.
+ *
+ * <p>Serialization logic is implemented as a {@link DataStreamCodec}.
+ *
+ * @param <T> The type of object to serialize / deserialize.
+ */
+public final class DataStreamFileCodec<T> {
+ private final File mFile;
+ private final DataStreamCodec<T> mCodec;
+
+ /**
+ * Constructs an instance to serialize to or deserialize from the given file, with the given
+ * serialization / deserialization strategy.
+ */
+ public DataStreamFileCodec(File file, DataStreamCodec<T> codec) {
+ mFile = file;
+ mCodec = codec;
+ }
+
+ /**
+ * Deserializes a {@code T} from the file, automatically closing input streams.
+ *
+ * @return The deserialized object.
+ * @throws IOException if an IO error occurred.
+ */
+ public T deserialize() throws IOException {
+ try (
+ FileInputStream fileInputStream = new FileInputStream(mFile);
+ DataInputStream dataInputStream = new DataInputStream(fileInputStream)
+ ) {
+ return mCodec.deserialize(dataInputStream);
+ }
+ }
+
+ /**
+ * Serializes {@code t} to the file, automatically flushing and closing output streams.
+ *
+ * @param t The object to serialize.
+ * @throws IOException if an IO error occurs.
+ */
+ public void serialize(T t) throws IOException {
+ try (
+ FileOutputStream fileOutputStream = new FileOutputStream(mFile);
+ BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
+ DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream)
+ ) {
+ mCodec.serialize(t, dataOutputStream);
+ dataOutputStream.flush();
+ }
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/utils/PasswordUtils.java b/services/backup/java/com/android/server/backup/utils/PasswordUtils.java
index 12fc927..9c5e283 100644
--- a/services/backup/java/com/android/server/backup/utils/PasswordUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/PasswordUtils.java
@@ -123,8 +123,7 @@
int rounds) {
try {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
- KeySpec
- ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE);
+ KeySpec ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE);
return keyFactory.generateSecret(ks);
} catch (InvalidKeySpecException e) {
Slog.e(TAG, "Invalid key spec for PBKDF2!");
diff --git a/services/backup/java/com/android/server/backup/utils/SparseArrayUtils.java b/services/backup/java/com/android/server/backup/utils/SparseArrayUtils.java
new file mode 100644
index 0000000..954d714
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/utils/SparseArrayUtils.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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.backup.utils;
+
+import android.util.SparseArray;
+
+import java.util.HashSet;
+
+/**
+ * Helper functions for manipulating instances of {@link SparseArray}.
+ */
+public final class SparseArrayUtils {
+ // Statics only
+ private SparseArrayUtils() {}
+
+ /**
+ * Given a {@link SparseArray<HashSet>}, returns a new {@link HashSet} containing every element
+ * from every set in the array.
+ *
+ * @param sets The array of sets from which to take the union.
+ * @param <V> The type of element contained in the set.
+ * @return The complete set.
+ */
+ public static<V> HashSet<V> union(SparseArray<HashSet<V>> sets) {
+ HashSet<V> unionSet = new HashSet<>();
+ int n = sets.size();
+ for (int i = 0; i < n; i++) {
+ HashSet<V> ithSet = sets.valueAt(i);
+ if (ithSet != null) {
+ unionSet.addAll(ithSet);
+ }
+ }
+ return unionSet;
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index f47b0d3..f2f01cf 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -57,6 +57,7 @@
import android.provider.Settings;
import android.provider.SettingsStringUtil.ComponentNameSet;
import android.text.BidiFormatter;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.ExceptionUtils;
import android.util.Log;
@@ -83,6 +84,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
@@ -247,9 +249,9 @@
throws RemoteException {
checkCallerIsSystemOr(callingPackage, userId);
checkUsesFeature(callingPackage, getCallingUserId());
- return CollectionUtils.map(
+ return new ArrayList<>(CollectionUtils.map(
readAllAssociations(userId, callingPackage),
- a -> a.deviceAddress);
+ a -> a.deviceAddress));
}
//TODO also revoke notification access
@@ -495,20 +497,20 @@
new Association(userId, deviceAddress, priviledgedPackage)));
}
- private void updateAssociations(Function<List<Association>, List<Association>> update) {
+ private void updateAssociations(Function<Set<Association>, Set<Association>> update) {
updateAssociations(update, getCallingUserId());
}
- private void updateAssociations(Function<List<Association>, List<Association>> update,
+ private void updateAssociations(Function<Set<Association>, Set<Association>> update,
int userId) {
final AtomicFile file = getStorageFileForUser(userId);
synchronized (file) {
- List<Association> associations = readAllAssociations(userId);
- final List<Association> old = CollectionUtils.copyOf(associations);
+ Set<Association> associations = readAllAssociations(userId);
+ final Set<Association> old = CollectionUtils.copyOf(associations);
associations = update.apply(associations);
if (size(old) == size(associations)) return;
- List<Association> finalAssociations = associations;
+ Set<Association> finalAssociations = associations;
file.write((out) -> {
XmlSerializer xml = Xml.newSerializer();
try {
@@ -517,13 +519,12 @@
xml.startDocument(null, true);
xml.startTag(null, XML_TAG_ASSOCIATIONS);
- for (int i = 0; i < size(finalAssociations); i++) {
- Association association = finalAssociations.get(i);
+ CollectionUtils.forEach(finalAssociations, association -> {
xml.startTag(null, XML_TAG_ASSOCIATION)
- .attribute(null, XML_ATTR_PACKAGE, association.companionAppPackage)
- .attribute(null, XML_ATTR_DEVICE, association.deviceAddress)
- .endTag(null, XML_TAG_ASSOCIATION);
- }
+ .attribute(null, XML_ATTR_PACKAGE, association.companionAppPackage)
+ .attribute(null, XML_ATTR_DEVICE, association.deviceAddress)
+ .endTag(null, XML_TAG_ASSOCIATION);
+ });
xml.endTag(null, XML_TAG_ASSOCIATIONS);
xml.endDocument();
@@ -545,17 +546,17 @@
}
@Nullable
- private ArrayList<Association> readAllAssociations(int userId) {
+ private Set<Association> readAllAssociations(int userId) {
return readAllAssociations(userId, null);
}
@Nullable
- private ArrayList<Association> readAllAssociations(int userId, @Nullable String packageFilter) {
+ private Set<Association> readAllAssociations(int userId, @Nullable String packageFilter) {
final AtomicFile file = getStorageFileForUser(userId);
if (!file.getBaseFile().exists()) return null;
- ArrayList<Association> result = null;
+ ArraySet<Association> result = null;
final XmlPullParser parser = Xml.newPullParser();
synchronized (file) {
try (FileInputStream in = file.openRead()) {
@@ -627,12 +628,10 @@
public int onCommand(String cmd) {
switch (cmd) {
case "list": {
- ArrayList<Association> associations = readAllAssociations(getNextArgInt());
- for (int i = 0; i < size(associations); i++) {
- Association a = associations.get(i);
- getOutPrintWriter()
- .println(a.companionAppPackage + " " + a.deviceAddress);
- }
+ CollectionUtils.forEach(
+ readAllAssociations(getNextArgInt()),
+ a -> getOutPrintWriter()
+ .println(a.companionAppPackage + " " + a.deviceAddress));
} break;
case "associate": {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index a2e74b6..8200289 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1036,8 +1036,7 @@
/**
* Apply any relevant filters to {@link NetworkState} for the given UID. For
* example, this may mark the network as {@link DetailedState#BLOCKED} based
- * on {@link #isNetworkWithLinkPropertiesBlocked}, or
- * {@link NetworkInfo#isMetered()} based on network policies.
+ * on {@link #isNetworkWithLinkPropertiesBlocked}.
*/
private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) {
if (state == null || state.networkInfo == null || state.linkProperties == null) return;
@@ -1048,15 +1047,6 @@
if (mLockdownTracker != null) {
mLockdownTracker.augmentNetworkInfo(state.networkInfo);
}
-
- // TODO: apply metered state closer to NetworkAgentInfo
- final long token = Binder.clearCallingIdentity();
- try {
- state.networkInfo.setMetered(mPolicyManager.isNetworkMetered(state));
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(token);
- }
}
/**
@@ -1326,30 +1316,24 @@
}
@Override
+ @Deprecated
public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
- enforceAccessPermission();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- final NetworkState state = getUnfilteredActiveNetworkState(uid);
- if (state.networkInfo != null) {
- try {
- return mPolicyManager.getNetworkQuotaInfo(state);
- } catch (RemoteException e) {
- }
- }
- return null;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ Log.w(TAG, "Shame on UID " + Binder.getCallingUid()
+ + " for calling the hidden API getNetworkQuotaInfo(). Shame!");
+ return new NetworkQuotaInfo();
}
@Override
public boolean isActiveNetworkMetered() {
enforceAccessPermission();
- final NetworkInfo info = getActiveNetworkInfo();
- return (info != null) ? info.isMetered() : false;
+ final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork());
+ if (caps != null) {
+ return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ } else {
+ // Always return the most conservative value
+ return true;
+ }
}
private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
@@ -2759,7 +2743,8 @@
enforceAccessPermission();
NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai != null && !nai.networkInfo.isMetered()) {
+ if (nai != null && nai.networkCapabilities
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) {
return ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index b88bbc1..2f9b861 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -206,7 +206,11 @@
T get(int key) {
T val = mArray.get(key);
- val.checkOwnerOrSystemAndThrow();
+ // The value should never be null unless the resource doesn't exist
+ // (since we do not allow null resources to be added).
+ if (val != null) {
+ val.checkOwnerOrSystemAndThrow();
+ }
return val;
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 8ea334d..7959e39 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.SHUTDOWN;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
@@ -55,6 +56,7 @@
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkManagementEventObserver;
+import android.net.ITetheringStatsProvider;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -225,6 +227,10 @@
private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
+ @GuardedBy("mTetheringStatsProviders")
+ private final HashMap<ITetheringStatsProvider, String>
+ mTetheringStatsProviders = Maps.newHashMap();
+
/**
* If both locks need to be held, then they should be obtained in the order:
* first {@link #mQuotaLock} and then {@link #mRulesLock}.
@@ -331,6 +337,10 @@
Watchdog.getInstance().addMonitor(this);
LocalServices.addService(NetworkManagementInternal.class, new LocalService());
+
+ synchronized (mTetheringStatsProviders) {
+ mTetheringStatsProviders.put(new NetdTetheringStatsProvider(), "netd");
+ }
}
@VisibleForTesting
@@ -520,6 +530,23 @@
}
}
+ @Override
+ public void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name) {
+ mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+ Preconditions.checkNotNull(provider);
+ synchronized(mTetheringStatsProviders) {
+ mTetheringStatsProviders.put(provider, name);
+ }
+ }
+
+ @Override
+ public void unregisterTetheringStatsProvider(ITetheringStatsProvider provider) {
+ mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+ synchronized(mTetheringStatsProviders) {
+ mTetheringStatsProviders.remove(provider);
+ }
+ }
+
// Sync the state of the given chain with the native daemon.
private void syncFirewallChainLocked(int chain, String name) {
SparseIntArray rules;
@@ -1789,14 +1816,16 @@
}
}
- @Override
- public NetworkStats getNetworkStatsTethering() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
- try {
- final NativeDaemonEvent[] events = mConnector.executeForList(
- "bandwidth", "gettetherstats");
+ private class NetdTetheringStatsProvider extends ITetheringStatsProvider.Stub {
+ @Override
+ public NetworkStats getTetherStats() {
+ final NativeDaemonEvent[] events;
+ try {
+ events = mConnector.executeForList("bandwidth", "gettetherstats");
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
for (NativeDaemonEvent event : events) {
if (event.getCode() != TetheringStatsListResult) continue;
@@ -1822,8 +1851,24 @@
throw new IllegalStateException("problem parsing tethering stats: " + event);
}
}
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ return stats;
+ }
+ }
+
+ @Override
+ public NetworkStats getNetworkStatsTethering() {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
+ synchronized (mTetheringStatsProviders) {
+ for (ITetheringStatsProvider provider: mTetheringStatsProviders.keySet()) {
+ try {
+ stats.combineAllValues(provider.getTetherStats());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Problem reading tethering stats from " +
+ mTetheringStatsProviders.get(provider) + ": " + e);
+ }
+ }
}
return stats;
}
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 72ff606..581914d 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.os.SystemClock;
import android.os.Trace;
import android.util.Slog;
@@ -118,14 +119,14 @@
// Register it.
mServices.add(service);
// Start it.
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onStart");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
/**
@@ -146,7 +147,7 @@
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, service.getClass().getName());
try {
service.onBootPhase(mCurrentPhase);
@@ -156,7 +157,7 @@
+ ": onBootPhase threw an exception during phase "
+ mCurrentPhase, ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onBootPhase");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
} finally {
@@ -178,14 +179,14 @@
final SystemService service = mServices.get(i);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onStartUser "
+ service.getClass().getName());
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onStartUser(userHandle);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting start of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onStartUser ");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStartUser ");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
@@ -197,14 +198,14 @@
final SystemService service = mServices.get(i);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onUnlockUser "
+ service.getClass().getName());
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onUnlockUser(userHandle);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting unlock of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onUnlockUser ");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onUnlockUser ");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
@@ -216,14 +217,14 @@
final SystemService service = mServices.get(i);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onSwitchUser "
+ service.getClass().getName());
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onSwitchUser(userHandle);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting switch of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onSwitchUser");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onSwitchUser");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
@@ -235,14 +236,14 @@
final SystemService service = mServices.get(i);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onStopUser "
+ service.getClass().getName());
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onStopUser(userHandle);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting stop of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onStopUser");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStopUser");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
@@ -254,14 +255,14 @@
final SystemService service = mServices.get(i);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onCleanupUser "
+ service.getClass().getName());
- long time = System.currentTimeMillis();
+ long time = SystemClock.elapsedRealtime();
try {
service.onCleanupUser(userHandle);
} catch (Exception ex) {
Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle
+ " to service " + service.getClass().getName(), ex);
}
- warnIfTooLong(System.currentTimeMillis() - time, service, "onCleanupUser");
+ warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onCleanupUser");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 6d9d874..80d39f5 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -857,7 +857,7 @@
Slog.e(TAG, "Remove the spell checker bind unexpectedly.");
synchronized (mLock) {
final int size = mListeners.getRegisteredCallbackCount();
- for (int i = 0; i < size; ++i) {
+ for (int i = size - 1; i >= 0; --i) {
mListeners.unregister(mListeners.getRegisteredCallbackItem(i));
}
mPendingSessionRequests.clear();
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index c68e5d6..4733840 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -48,6 +48,7 @@
import android.os.WorkSource;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
+import android.util.DebugUtils;
import android.util.Slog;
import android.view.InputDevice;
import android.media.AudioAttributes;
@@ -60,10 +61,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
import java.util.LinkedList;
-import java.util.ListIterator;
public class VibratorService extends IVibratorService.Stub
implements InputManager.InputDeviceListener {
@@ -948,6 +946,21 @@
}
private int runVibrate() {
+ try {
+ final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ZEN_MODE);
+ if (zenMode != Settings.Global.ZEN_MODE_OFF) {
+ try (PrintWriter pw = getOutPrintWriter();) {
+ pw.print("Ignoring because device is on DND mode ");
+ pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
+ zenMode));
+ return 0;
+ }
+ }
+ } catch (SettingNotFoundException e) {
+ // ignore
+ }
+
final long duration = Long.parseLong(getNextArgRequired());
if (duration > MAX_VIBRATION_MS) {
throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
@@ -972,7 +985,8 @@
pw.println(" Prints this help text.");
pw.println("");
pw.println(" vibrate duration [description]");
- pw.println(" Vibrates for duration milliseconds.");
+ pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
+ pw.println(" (Do Not Disturb) mode.");
pw.println("");
}
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index b18fa32..aceedf1 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -85,8 +85,9 @@
"android.hardware.bluetooth@1.0::IBluetoothHci",
"android.hardware.camera.provider@2.4::ICameraProvider",
"android.hardware.graphics.composer@2.1::IComposer",
- "android.hardware.vr@1.0::IVr",
- "android.hardware.media.omx@1.0::IOmx"
+ "android.hardware.media.omx@1.0::IOmx",
+ "android.hardware.sensors@1.0::ISensors",
+ "android.hardware.vr@1.0::IVr"
);
static Watchdog sWatchdog;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index a54fe72..c6f2fc0 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -5180,6 +5180,28 @@
fout.println();
mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
+
+ boolean isUserUnlocked;
+ synchronized (mUsers) {
+ isUserUnlocked = isLocalUnlockedUser(userAccounts.userId);
+ }
+ // Following logs are printed only when user is unlocked.
+ if (!isUserUnlocked) {
+ return;
+ }
+ fout.println();
+ synchronized (userAccounts.dbLock) {
+ Map<Account, Map<String, Integer>> allVisibilityValues =
+ userAccounts.accountsDb.findAllVisibilityValues();
+ fout.println("Account visibility:");
+ for (Account account : allVisibilityValues.keySet()) {
+ fout.println(" " + account.name);
+ Map<String, Integer> visibilities = allVisibilityValues.get(account);
+ for (Entry<String, Integer> entry : visibilities.entrySet()) {
+ fout.println(" " + entry.getKey() + ", " + entry.getValue());
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 03adcc4..97be508 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6715,7 +6715,6 @@
mActiveUids.put(proc.uid, uidRec);
EventLogTags.writeAmUidRunning(uidRec.uid);
noteUidProcessState(uidRec.uid, uidRec.curProcState);
- enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
}
proc.uidRecord = uidRec;
@@ -17368,23 +17367,41 @@
ArrayList<MemItem> catMems = new ArrayList<MemItem>();
catMems.add(new MemItem("Native", "Native", nativePss, nativeSwapPss, -1));
- final MemItem dalvikItem =
- new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, -2);
- if (dalvikSubitemPss.length > 0) {
- dalvikItem.subitems = new ArrayList<MemItem>();
- for (int j=0; j<dalvikSubitemPss.length; j++) {
- final String name = Debug.MemoryInfo.getOtherLabel(
- Debug.MemoryInfo.NUM_OTHER_STATS + j);
- dalvikItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
- dalvikSubitemSwapPss[j], j));
- }
- }
- catMems.add(dalvikItem);
+ final int dalvikId = -2;
+ catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, dalvikId));
catMems.add(new MemItem("Unknown", "Unknown", otherPss, otherSwapPss, -3));
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
String label = Debug.MemoryInfo.getOtherLabel(j);
catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], j));
}
+ if (dalvikSubitemPss.length > 0) {
+ // Add dalvik subitems.
+ for (MemItem memItem : catMems) {
+ int memItemStart = 0, memItemEnd = 0;
+ if (memItem.id == dalvikId) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_DALVIK_OTHER) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_OTHER_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_OTHER_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_DEX) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DEX_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DEX_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_ART) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_ART_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_ART_END;
+ } else {
+ continue; // No subitems, continue.
+ }
+ memItem.subitems = new ArrayList<MemItem>();
+ for (int j=memItemStart; j<=memItemEnd; j++) {
+ final String name = Debug.MemoryInfo.getOtherLabel(
+ Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ memItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
+ dalvikSubitemSwapPss[j], j));
+ }
+ }
+ }
ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
for (int j=0; j<oomPss.length; j++) {
@@ -22808,8 +22825,9 @@
for (int i=mActiveUids.size()-1; i>=0; i--) {
final UidRecord uidRec = mActiveUids.valueAt(i);
int uidChange = UidRecord.CHANGE_PROCSTATE;
- if (uidRec.setProcState != uidRec.curProcState
- || uidRec.setWhitelist != uidRec.curWhitelist) {
+ if (uidRec.curProcState != ActivityManager.PROCESS_STATE_NONEXISTENT
+ && (uidRec.setProcState != uidRec.curProcState
+ || uidRec.setWhitelist != uidRec.curWhitelist)) {
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Changes in " + uidRec + ": proc state from " + uidRec.setProcState
+ " to " + uidRec.curProcState + ", whitelist from " + uidRec.setWhitelist
@@ -22830,7 +22848,7 @@
mConstants.BACKGROUND_SETTLE_TIME);
}
}
- if (!uidRec.setIdle) {
+ if (uidRec.idle && !uidRec.setIdle) {
uidChange = UidRecord.CHANGE_IDLE;
}
} else {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 83eea98..9273b3c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -23,6 +23,7 @@
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
+import android.app.IUidObserver;
import android.app.ProfilerInfo;
import android.app.WaitResult;
import android.app.usage.ConfigurationStats;
@@ -184,6 +185,8 @@
return runMakeIdle(pw);
case "monitor":
return runMonitor(pw);
+ case "watch-uids":
+ return runWatchUids(pw);
case "hang":
return runHang(pw);
case "restart":
@@ -1294,6 +1297,141 @@
return 0;
}
+ static final class MyUidObserver extends IUidObserver.Stub {
+ final IActivityManager mInterface;
+ final PrintWriter mPw;
+ final InputStream mInput;
+
+ static final int STATE_NORMAL = 0;
+
+ int mState;
+
+ MyUidObserver(IActivityManager iam, PrintWriter pw, InputStream input) {
+ mInterface = iam;
+ mPw = pw;
+ mInput = input;
+ }
+
+ @Override
+ public void onUidStateChanged(int uid, int procState, long procStateSeq) throws RemoteException {
+ synchronized (this) {
+ mPw.print(uid);
+ mPw.print(" procstate ");
+ mPw.print(ProcessList.makeProcStateString(procState));
+ mPw.print(" seq ");
+ mPw.println(procStateSeq);
+ mPw.flush();
+ }
+ }
+
+ @Override
+ public void onUidGone(int uid, boolean disabled) throws RemoteException {
+ synchronized (this) {
+ mPw.print(uid);
+ mPw.print(" gone");
+ if (disabled) {
+ mPw.print(" disabled");
+ }
+ mPw.println();
+ mPw.flush();
+ }
+ }
+
+ @Override
+ public void onUidActive(int uid) throws RemoteException {
+ synchronized (this) {
+ mPw.print(uid);
+ mPw.println(" active");
+ mPw.flush();
+ }
+ }
+
+ @Override
+ public void onUidIdle(int uid, boolean disabled) throws RemoteException {
+ synchronized (this) {
+ mPw.print(uid);
+ mPw.print(" idle");
+ if (disabled) {
+ mPw.print(" disabled");
+ }
+ mPw.println();
+ mPw.flush();
+ }
+ }
+
+ @Override
+ public void onUidCachedChanged(int uid, boolean cached) throws RemoteException {
+ synchronized (this) {
+ mPw.print(uid);
+ mPw.println(cached ? " cached" : " uncached");
+ mPw.flush();
+ }
+ }
+
+ void printMessageForState() {
+ switch (mState) {
+ case STATE_NORMAL:
+ mPw.println("Watching uid states... available commands:");
+ break;
+ }
+ mPw.println("(q)uit: finish watching");
+ }
+
+ void run() throws RemoteException {
+ try {
+ printMessageForState();
+ mPw.flush();
+
+ mInterface.registerUidObserver(this, ActivityManager.UID_OBSERVER_ACTIVE
+ | ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_PROCSTATE
+ | ActivityManager.UID_OBSERVER_IDLE | ActivityManager.UID_OBSERVER_CACHED,
+ ActivityManager.PROCESS_STATE_UNKNOWN, null);
+ mState = STATE_NORMAL;
+
+ InputStreamReader converter = new InputStreamReader(mInput);
+ BufferedReader in = new BufferedReader(converter);
+ String line;
+
+ while ((line = in.readLine()) != null) {
+ boolean addNewline = true;
+ if (line.length() <= 0) {
+ addNewline = false;
+ } else if ("q".equals(line) || "quit".equals(line)) {
+ break;
+ } else {
+ mPw.println("Invalid command: " + line);
+ }
+
+ synchronized (this) {
+ if (addNewline) {
+ mPw.println("");
+ }
+ printMessageForState();
+ mPw.flush();
+ }
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace(mPw);
+ mPw.flush();
+ } finally {
+ mInterface.unregisterUidObserver(this);
+ }
+ }
+ }
+
+ int runWatchUids(PrintWriter pw) throws RemoteException {
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+
+ MyUidObserver controller = new MyUidObserver(mInterface, pw, getRawInputStream());
+ controller.run();
+ return 0;
+ }
+
int runHang(PrintWriter pw) throws RemoteException {
String opt;
boolean allowRestart = false;
@@ -2599,6 +2737,8 @@
pw.println(" monitor [--gdb <port>]");
pw.println(" Start monitoring for crashes or ANRs.");
pw.println(" --gdb: start gdbserv on the given port at crash/ANR");
+ pw.println(" watch-uids [--gdb <port>]");
+ pw.println(" Start watching for and reporting uid state changes.");
pw.println(" hang [--allow-restart]");
pw.println(" Hang the system.");
pw.println(" --allow-restart: allow watchdog to perform normal system restart");
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 82b2566..3133a51 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -21,6 +21,7 @@
import android.content.IntentFilter;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceProxy;
+import android.metrics.LogMaker;
import android.nfc.INfcAdapter;
import android.os.Binder;
import android.os.Handler;
@@ -28,15 +29,23 @@
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserManager;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import java.util.Set;
/**
@@ -65,6 +74,9 @@
private static final int RETRY_DELAY_TIME = 20; //ms
+ // Maximum entries to keep in usage history before dumping out
+ private static final int MAX_USAGE_HISTORY = 100;
+
private final Context mContext;
private final ServiceThread mHandlerThread;
private final Handler mHandler;
@@ -76,14 +88,52 @@
private ICameraService mCameraServiceRaw;
- private final ArraySet<String> mActiveCameraIds = new ArraySet<>();
-
+ private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>();
+ private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>();
+ private final MetricsLogger mLogger = new MetricsLogger();
private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc";
private static final String NFC_SERVICE_BINDER_NAME = "nfc";
private static final IBinder nfcInterfaceToken = new Binder();
private final boolean mNotifyNfc;
- private int mActiveCameraCount = 0;
+
+ /**
+ * Structure to track camera usage
+ */
+ private static class CameraUsageEvent {
+ public final int mCameraFacing;
+ public final String mClientName;
+
+ private boolean mCompleted;
+ private long mDurationOrStartTimeMs; // Either start time, or duration once completed
+
+ public CameraUsageEvent(int facing, String clientName) {
+ mCameraFacing = facing;
+ mClientName = clientName;
+ mDurationOrStartTimeMs = SystemClock.elapsedRealtime();
+ mCompleted = false;
+ }
+
+ public void markCompleted() {
+ if (mCompleted) {
+ return;
+ }
+ mCompleted = true;
+ mDurationOrStartTimeMs = SystemClock.elapsedRealtime() - mDurationOrStartTimeMs;
+ if (CameraServiceProxy.DEBUG) {
+ Slog.v(TAG, "A camera facing " + cameraFacingToString(mCameraFacing) +
+ " was in use by " + mClientName + " for " +
+ mDurationOrStartTimeMs + " ms");
+ }
+ }
+
+ /**
+ * Return duration of camera usage event, or 0 if the event is not done
+ */
+ public long getDuration() {
+ return mCompleted ? mDurationOrStartTimeMs : 0;
+ }
+ }
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
@@ -120,10 +170,11 @@
public void notifyCameraState(String cameraId, int newCameraState, int facing,
String clientName) {
String state = cameraStateToString(newCameraState);
- if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facing + " state now " +
+ String facingStr = cameraFacingToString(facing);
+ if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facingStr + " state now " +
state + " for client " + clientName);
- updateActivityCount(cameraId, newCameraState);
+ updateActivityCount(cameraId, newCameraState, facing, clientName);
}
};
@@ -169,6 +220,9 @@
mContext.registerReceiver(mIntentReceiver, filter);
publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy);
+ publishLocalService(CameraServiceProxy.class, this);
+
+ CameraStatsJobService.schedule(mContext);
}
@Override
@@ -198,8 +252,8 @@
mCameraServiceRaw = null;
// All cameras reset to idle on camera service death
- boolean wasEmpty = mActiveCameraIds.isEmpty();
- mActiveCameraIds.clear();
+ boolean wasEmpty = mActiveCameraUsage.isEmpty();
+ mActiveCameraUsage.clear();
if ( mNotifyNfc && !wasEmpty ) {
notifyNfcService(/*enablePolling*/ true);
@@ -207,6 +261,46 @@
}
}
+ /**
+ * Dump camera usage events to log.
+ * Package-private
+ */
+ void dumpUsageEvents() {
+ synchronized(mLock) {
+ // Randomize order of events so that it's not meaningful
+ Collections.shuffle(mCameraUsageHistory);
+ for (CameraUsageEvent e : mCameraUsageHistory) {
+ if (DEBUG) {
+ Slog.v(TAG, "Camera: " + e.mClientName + " used a camera facing " +
+ cameraFacingToString(e.mCameraFacing) + " for " +
+ e.getDuration() + " ms");
+ }
+ int subtype = 0;
+ switch(e.mCameraFacing) {
+ case ICameraServiceProxy.CAMERA_FACING_BACK:
+ subtype = MetricsEvent.CAMERA_BACK_USED;
+ break;
+ case ICameraServiceProxy.CAMERA_FACING_FRONT:
+ subtype = MetricsEvent.CAMERA_FRONT_USED;
+ break;
+ case ICameraServiceProxy.CAMERA_FACING_EXTERNAL:
+ subtype = MetricsEvent.CAMERA_EXTERNAL_USED;
+ break;
+ default:
+ continue;
+ }
+ LogMaker l = new LogMaker(MetricsEvent.ACTION_CAMERA_EVENT)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .setSubtype(subtype)
+ .setLatency(e.getDuration())
+ .setPackageName(e.mClientName);
+ mLogger.write(l);
+ }
+ mCameraUsageHistory.clear();
+ }
+ CameraStatsJobService.schedule(mContext);
+ }
+
private void switchUserLocked(int userHandle) {
Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle);
mLastUser = userHandle;
@@ -274,21 +368,35 @@
return true;
}
- private void updateActivityCount(String cameraId, int newCameraState) {
+ private void updateActivityCount(String cameraId, int newCameraState, int facing, String clientName) {
synchronized(mLock) {
- boolean wasEmpty = mActiveCameraIds.isEmpty();
+ // Update active camera list and notify NFC if necessary
+ boolean wasEmpty = mActiveCameraUsage.isEmpty();
switch (newCameraState) {
case ICameraServiceProxy.CAMERA_STATE_OPEN:
break;
case ICameraServiceProxy.CAMERA_STATE_ACTIVE:
- mActiveCameraIds.add(cameraId);
+ CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName);
+ CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent);
+ if (oldEvent != null) {
+ Slog.w(TAG, "Camera " + cameraId + " was already marked as active");
+ oldEvent.markCompleted();
+ mCameraUsageHistory.add(oldEvent);
+ }
break;
case ICameraServiceProxy.CAMERA_STATE_IDLE:
case ICameraServiceProxy.CAMERA_STATE_CLOSED:
- mActiveCameraIds.remove(cameraId);
+ CameraUsageEvent doneEvent = mActiveCameraUsage.remove(cameraId);
+ if (doneEvent != null) {
+ doneEvent.markCompleted();
+ mCameraUsageHistory.add(doneEvent);
+ if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) {
+ dumpUsageEvents();
+ }
+ }
break;
}
- boolean isEmpty = mActiveCameraIds.isEmpty();
+ boolean isEmpty = mActiveCameraUsage.isEmpty();
if ( mNotifyNfc && (wasEmpty != isEmpty) ) {
notifyNfcService(isEmpty);
}
@@ -332,4 +440,15 @@
}
return "CAMERA_STATE_UNKNOWN";
}
+
+ private static String cameraFacingToString(int cameraFacing) {
+ switch (cameraFacing) {
+ case ICameraServiceProxy.CAMERA_FACING_BACK: return "CAMERA_FACING_BACK";
+ case ICameraServiceProxy.CAMERA_FACING_FRONT: return "CAMERA_FACING_FRONT";
+ case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: return "CAMERA_FACING_EXTERNAL";
+ default: break;
+ }
+ return "CAMERA_FACING_UNKNOWN";
+ }
+
}
diff --git a/services/core/java/com/android/server/camera/CameraStatsJobService.java b/services/core/java/com/android/server/camera/CameraStatsJobService.java
new file mode 100644
index 0000000..b8a6846
--- /dev/null
+++ b/services/core/java/com/android/server/camera/CameraStatsJobService.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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/LICENSE2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.server.camera;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.util.Slog;
+
+import java.util.concurrent.TimeUnit;
+
+import com.android.server.LocalServices;
+
+/**
+ * A JobService to periodically collect camera usage stats.
+ */
+public class CameraStatsJobService extends JobService {
+ private static final String TAG = "CameraStatsJobService";
+
+ // Must be unique within UID (system service)
+ private static final int CAMERA_REPORTING_JOB_ID = 0xCA3E7A;
+
+ private static ComponentName sCameraStatsJobServiceName = new ComponentName(
+ "android",
+ CameraStatsJobService.class.getName());
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ CameraServiceProxy serviceProxy = LocalServices.getService(CameraServiceProxy.class);
+ if (serviceProxy == null) {
+ Slog.w(TAG, "Can't collect camera usage stats - no camera service proxy found");
+ return false;
+ }
+
+ serviceProxy.dumpUsageEvents();
+ return false;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ // All work is done in onStartJob, so nothing to stop here
+ return false;
+ }
+
+ public static void schedule(Context context) {
+
+ JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ if (js == null) {
+ Slog.e(TAG, "Can't collect camera usage stats - no Job Scheduler");
+ return;
+ }
+ js.schedule(new JobInfo.Builder(CAMERA_REPORTING_JOB_ID, sCameraStatsJobServiceName)
+ .setMinimumLatency(TimeUnit.DAYS.toMillis(1))
+ .setRequiresDeviceIdle(true)
+ .build());
+
+ }
+
+}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 1fb944f..b0be8f7 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -214,7 +214,7 @@
final Handler smHandler = mTetherMasterSM.getHandler();
mOffloadController = new OffloadController(smHandler,
deps.getOffloadHardwareInterface(smHandler, mLog),
- mContext.getContentResolver(),
+ mContext.getContentResolver(), mNMService,
mLog);
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
@@ -1759,6 +1759,11 @@
pw.decreaseIndent();
}
+ pw.println("Hardware offload:");
+ pw.increaseIndent();
+ mOffloadController.dump(pw);
+ pw.decreaseIndent();
+
pw.println("Log:");
pw.increaseIndent();
if (argsContain(args, SHORT_ARG)) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index b473867..1a5ff77 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -16,24 +16,38 @@
package com.android.server.connectivity.tethering;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.TrafficStats.UID_TETHERING;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
import android.content.ContentResolver;
+import android.net.ITetheringStatsProvider;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkStats;
import android.net.RouteInfo;
import android.net.util.SharedLog;
import android.os.Handler;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.SystemClock;
import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.android.internal.util.IndentingPrintWriter;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* A class to encapsulate the business logic of programming the tethering
@@ -44,6 +58,8 @@
public class OffloadController {
private static final String TAG = OffloadController.class.getSimpleName();
+ private static final int STATS_FETCH_TIMEOUT_MS = 1000;
+
private final Handler mHandler;
private final OffloadHardwareInterface mHwInterface;
private final ContentResolver mContentResolver;
@@ -59,14 +75,25 @@
// prefixes representing only the locally-assigned IP addresses.
private Set<String> mLastLocalPrefixStrs;
+ // Maps upstream interface names to offloaded traffic statistics.
+ private HashMap<String, OffloadHardwareInterface.ForwardedStats>
+ mForwardedStats = new HashMap<>();
+
public OffloadController(Handler h, OffloadHardwareInterface hwi,
- ContentResolver contentResolver, SharedLog log) {
+ ContentResolver contentResolver, INetworkManagementService nms, SharedLog log) {
mHandler = h;
mHwInterface = hwi;
mContentResolver = contentResolver;
mLog = log.forSubComponent(TAG);
mExemptPrefixes = new HashSet<>();
mLastLocalPrefixStrs = new HashSet<>();
+
+ try {
+ nms.registerTetheringStatsProvider(
+ new OffloadTetheringStatsProvider(), getClass().getSimpleName());
+ } catch (RemoteException e) {
+ mLog.e("Cannot register offload stats provider: " + e);
+ }
}
public void start() {
@@ -138,6 +165,7 @@
public void stop() {
final boolean wasStarted = started();
+ updateStatsForCurrentUpstream();
mUpstreamLinkProperties = null;
mHwInterface.stopOffloadControl();
mControlInitialized = false;
@@ -145,16 +173,76 @@
if (wasStarted) mLog.log("tethering offload stopped");
}
+ private class OffloadTetheringStatsProvider extends ITetheringStatsProvider.Stub {
+ @Override
+ public NetworkStats getTetherStats() {
+ NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
+ CountDownLatch latch = new CountDownLatch(1);
+
+ mHandler.post(() -> {
+ try {
+ NetworkStats.Entry entry = new NetworkStats.Entry();
+ entry.set = SET_DEFAULT;
+ entry.tag = TAG_NONE;
+ entry.uid = UID_TETHERING;
+
+ updateStatsForCurrentUpstream();
+
+ for (String iface : mForwardedStats.keySet()) {
+ entry.iface = iface;
+ entry.rxBytes = mForwardedStats.get(iface).rxBytes;
+ entry.txBytes = mForwardedStats.get(iface).txBytes;
+ stats.addValues(entry);
+ }
+ } finally {
+ latch.countDown();
+ }
+ });
+
+ try {
+ latch.await(STATS_FETCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ mLog.e("Tethering stats fetch timed out after " + STATS_FETCH_TIMEOUT_MS + "ms");
+ }
+
+ return stats;
+ }
+ }
+
+ private void maybeUpdateStats(String iface) {
+ if (TextUtils.isEmpty(iface)) {
+ return;
+ }
+
+ if (!mForwardedStats.containsKey(iface)) {
+ mForwardedStats.put(iface, new OffloadHardwareInterface.ForwardedStats());
+ }
+ mForwardedStats.get(iface).add(mHwInterface.getForwardedStats(iface));
+ }
+
+ private void updateStatsForCurrentUpstream() {
+ if (mUpstreamLinkProperties != null) {
+ maybeUpdateStats(mUpstreamLinkProperties.getInterfaceName());
+ }
+ }
+
public void setUpstreamLinkProperties(LinkProperties lp) {
if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return;
+ String prevUpstream = (mUpstreamLinkProperties != null) ?
+ mUpstreamLinkProperties.getInterfaceName() : null;
+
mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null;
+
// TODO: examine return code and decide what to do if programming
// upstream parameters fails (probably just wait for a subsequent
// onOffloadEvent() callback to tell us offload is available again and
// then reapply all state).
computeAndPushLocalPrefixes();
pushUpstreamParameters();
+
+ // Update stats after we've told the hardware to change routing so we don't miss packets.
+ maybeUpdateStats(prevUpstream);
}
public void setLocalPrefixes(Set<IpPrefix> localPrefixes) {
@@ -262,4 +350,16 @@
for (IpPrefix pfx : prefixSet) localPrefixStrs.add(pfx.toString());
return localPrefixStrs;
}
+
+ public void dump(IndentingPrintWriter pw) {
+ if (isOffloadDisabled()) {
+ pw.println("Offload disabled");
+ return;
+ }
+ pw.println("Offload HALs " + (started() ? "started" : "not started"));
+ LinkProperties lp = mUpstreamLinkProperties;
+ String upstream = (lp != null) ? lp.getInterfaceName() : null;
+ pw.println("Current upstream: " + upstream);
+ pw.println("Exempt prefixes: " + mLastLocalPrefixStrs);
+ }
}
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index 1f02ebf..07f04b1 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -76,7 +76,7 @@
m.what = SyncManager.SyncHandler.MESSAGE_START_SYNC;
SyncOperation op = SyncOperation.maybeCreateFromJobExtras(params.getExtras());
- mLogger.log("onStopJob() jobid=", params.getJobId(), " op=", op);
+ mLogger.log("onStartJob() jobid=", params.getJobId(), " op=", op);
if (op == null) {
Slog.e(TAG, "Got invalid job " + params.getJobId());
@@ -131,4 +131,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index e82724d..d4abc08 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -16,6 +16,7 @@
package com.android.server.display;
+import android.app.ActivityManager;
import com.android.internal.app.IBatteryStats;
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
@@ -161,6 +162,9 @@
// True if should use light sensor to automatically determine doze screen brightness.
private final boolean mAllowAutoBrightnessWhileDozingConfig;
+ // Whether or not the color fade on screen on / off is enabled.
+ private final boolean mColorFadeEnabled;
+
// True if we should fade the screen while turning it off, false if we should play
// a stylish color fade animation instead.
private boolean mColorFadeFadesConfig;
@@ -407,6 +411,8 @@
mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
+
+ mColorFadeEnabled = !ActivityManager.isLowRamDeviceStatic();
mColorFadeFadesConfig = resources.getBoolean(
com.android.internal.R.bool.config_animateScreenLights);
@@ -497,17 +503,19 @@
// Initialize the power state object for the default display.
// In the future, we might manage multiple displays independently.
mPowerState = new DisplayPowerState(mBlanker,
- new ColorFade(Display.DEFAULT_DISPLAY));
+ mColorFadeEnabled ? new ColorFade(Display.DEFAULT_DISPLAY) : null);
- mColorFadeOnAnimator = ObjectAnimator.ofFloat(
- mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f);
- mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS);
- mColorFadeOnAnimator.addListener(mAnimatorListener);
+ if (mColorFadeEnabled) {
+ mColorFadeOnAnimator = ObjectAnimator.ofFloat(
+ mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f);
+ mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS);
+ mColorFadeOnAnimator.addListener(mAnimatorListener);
- mColorFadeOffAnimator = ObjectAnimator.ofFloat(
- mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
- mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
- mColorFadeOffAnimator.addListener(mAnimatorListener);
+ mColorFadeOffAnimator = ObjectAnimator.ofFloat(
+ mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
+ mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
+ mColorFadeOffAnimator.addListener(mAnimatorListener);
+ }
mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
@@ -784,9 +792,9 @@
// Note that we do not wait for the brightness ramp animation to complete before
// reporting the display is ready because we only need to ensure the screen is in the
// right power state even as it continues to converge on the desired brightness.
- final boolean ready = mPendingScreenOnUnblocker == null
- && !mColorFadeOnAnimator.isStarted()
- && !mColorFadeOffAnimator.isStarted()
+ final boolean ready = mPendingScreenOnUnblocker == null &&
+ (!mColorFadeEnabled ||
+ (!mColorFadeOnAnimator.isStarted() && !mColorFadeOffAnimator.isStarted()))
&& mPowerState.waitUntilClean(mCleanListener);
final boolean finished = ready
&& !mScreenBrightnessRampAnimator.isAnimating();
@@ -959,8 +967,8 @@
private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
// If there is already an animation in progress, don't interfere with it.
- if (mColorFadeOnAnimator.isStarted()
- || mColorFadeOffAnimator.isStarted()) {
+ if (mColorFadeEnabled &&
+ (mColorFadeOnAnimator.isStarted() || mColorFadeOffAnimator.isStarted())) {
if (target != Display.STATE_ON) {
return;
}
@@ -984,7 +992,7 @@
if (!setScreenState(Display.STATE_ON)) {
return; // screen on blocked
}
- if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
+ if (USE_COLOR_FADE_ON_ANIMATION && mColorFadeEnabled && mPowerRequest.isBrightOrDim()) {
// Perform screen on animation.
if (mPowerState.getColorFadeLevel() == 1.0f) {
mPowerState.dismissColorFade();
@@ -1060,6 +1068,10 @@
} else {
// Want screen off.
mPendingScreenOff = true;
+ if (!mColorFadeEnabled) {
+ mPowerState.setColorFadeLevel(0.0f);
+ }
+
if (mPowerState.getColorFadeLevel() == 0.0f) {
// Turn the screen off.
// A black surface is already hiding the contents of the screen.
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index e2fd0ac..d0c1580 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -174,7 +174,7 @@
* @return True if the electron beam was prepared.
*/
public boolean prepareColorFade(Context context, int mode) {
- if (!mColorFade.prepare(context, mode)) {
+ if (mColorFade == null || !mColorFade.prepare(context, mode)) {
mColorFadePrepared = false;
mColorFadeReady = true;
return false;
@@ -190,7 +190,7 @@
* Dismisses the color fade surface.
*/
public void dismissColorFade() {
- mColorFade.dismiss();
+ if (mColorFade != null) mColorFade.dismiss();
mColorFadePrepared = false;
mColorFadeReady = true;
}
@@ -199,7 +199,7 @@
* Dismisses the color fade resources.
*/
public void dismissColorFadeResources() {
- mColorFade.dismissResources();
+ if (mColorFade != null) mColorFade.dismissResources();
}
/**
@@ -269,7 +269,7 @@
pw.println(" mColorFadeDrawPending=" + mColorFadeDrawPending);
mPhotonicModulator.dump(pw);
- mColorFade.dump(pw);
+ if (mColorFade != null) mColorFade.dump(pw);
}
private void scheduleScreenUpdate() {
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 17c8928..78367fe 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -85,7 +85,7 @@
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
if (jobStatus.hasConnectivityConstraint()) {
- updateConstraintsSatisfied(jobStatus, null);
+ updateConstraintsSatisfied(jobStatus);
mTrackedJobs.add(jobStatus);
jobStatus.setTrackingController(JobStatus.TRACKING_CONNECTIVITY);
}
@@ -99,23 +99,25 @@
}
}
- private boolean updateConstraintsSatisfied(JobStatus jobStatus,
- NetworkCapabilities capabilities) {
+ private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
final int jobUid = jobStatus.getSourceUid();
final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobUid, ignoreBlocked);
- if (capabilities == null) {
- final Network network = mConnManager.getActiveNetworkForUid(jobUid, ignoreBlocked);
- capabilities = mConnManager.getNetworkCapabilities(network);
- }
+ final Network network = mConnManager.getActiveNetworkForUid(jobUid, ignoreBlocked);
+ final NetworkCapabilities capabilities = (network != null)
+ ? mConnManager.getNetworkCapabilities(network) : null;
- final boolean validated = capabilities != null
+ final boolean validated = (capabilities != null)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
- final boolean connected = info != null && info.isConnected();
+ final boolean connected = (info != null) && info.isConnected();
final boolean connectionUsable = connected && validated;
- final boolean metered = connected && info.isMetered();
- final boolean unmetered = connected && !info.isMetered();
- final boolean notRoaming = connected && !info.isRoaming();
+
+ final boolean metered = connected && (capabilities != null)
+ && !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ final boolean unmetered = connected && (capabilities != null)
+ && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ final boolean notRoaming = connected && (info != null)
+ && !info.isRoaming();
boolean changed = false;
changed |= jobStatus.setConnectivityConstraintSatisfied(connectionUsable);
@@ -148,13 +150,13 @@
* @param uid only update jobs belonging to this UID, or {@code -1} to
* update all tracked jobs.
*/
- private void updateTrackedJobs(int uid, NetworkCapabilities capabilities) {
+ private void updateTrackedJobs(int uid) {
synchronized (mLock) {
boolean changed = false;
for (int i = mTrackedJobs.size()-1; i >= 0; i--) {
final JobStatus js = mTrackedJobs.valueAt(i);
if (uid == -1 || uid == js.getSourceUid()) {
- changed |= updateConstraintsSatisfied(js, capabilities);
+ changed |= updateConstraintsSatisfied(js);
}
}
if (changed) {
@@ -187,7 +189,7 @@
if (DEBUG) {
Slog.v(TAG, "onCapabilitiesChanged() : " + networkCapabilities);
}
- updateTrackedJobs(-1, networkCapabilities);
+ updateTrackedJobs(-1);
}
@Override
@@ -195,7 +197,7 @@
if (DEBUG) {
Slog.v(TAG, "Network lost");
}
- updateTrackedJobs(-1, null);
+ updateTrackedJobs(-1);
}
};
@@ -205,7 +207,7 @@
if (DEBUG) {
Slog.v(TAG, "Uid rules changed for " + uid);
}
- updateTrackedJobs(uid, null);
+ updateTrackedJobs(uid);
}
@Override
@@ -218,7 +220,7 @@
if (DEBUG) {
Slog.v(TAG, "Background restriction change to " + restrictBackground);
}
- updateTrackedJobs(-1, null);
+ updateTrackedJobs(-1);
}
@Override
@@ -226,7 +228,7 @@
if (DEBUG) {
Slog.v(TAG, "Uid policy changed for " + uid);
}
- updateTrackedJobs(uid, null);
+ updateTrackedJobs(uid);
}
};
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 601dd94..83bb17e 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -2516,6 +2516,7 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder s = new StringBuilder();
+ s.append(" mStarted=").append(mStarted).append('\n');
s.append(" mFixInterval=").append(mFixInterval).append('\n');
s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 8d53447..a105c84 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1132,12 +1132,6 @@
fixateNewestUserKeyAuth(userId);
synchronizeUnifiedWorkChallengeForProfiles(userId, null);
notifyActivePasswordMetricsAvailable(null, userId);
-
- if (mStorage.getPersistentDataBlock() != null
- && LockPatternUtils.userOwnsFrpCredential(mUserManager.getUserInfo(userId))) {
- // If owner, write to persistent storage for FRP
- mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, userId, 0, null);
- }
return;
}
if (credential == null) {
@@ -1190,12 +1184,6 @@
// Refresh the auth token
doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
synchronizeUnifiedWorkChallengeForProfiles(userId, null);
- if (mStorage.getPersistentDataBlock() != null
- && LockPatternUtils.userOwnsFrpCredential(mUserManager.getUserInfo(userId))) {
- // If owner, write to persistent storage for FRP
- mStorage.writePersistentDataBlock(PersistentData.TYPE_GATEKEEPER, userId,
- requestedQuality, willStore.toBytes());
- }
} else {
throw new RemoteException("Failed to enroll " +
(credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
@@ -1443,18 +1431,12 @@
return response;
}
- final CredentialHash storedHash;
if (userId == USER_FRP) {
- PersistentData data = mStorage.readPersistentDataBlock();
- if (data.type != PersistentData.TYPE_GATEKEEPER) {
- Slog.wtf(TAG, "Expected PersistentData.TYPE_GATEKEEPER, but was: " + data.type);
- return VerifyCredentialResponse.ERROR;
- }
- return verifyFrpCredential(credential, credentialType, data, progressCallback);
- } else {
- storedHash = mStorage.readCredentialHash(userId);
+ Slog.wtf(TAG, "Unexpected FRP credential type, should be SP based.");
+ return VerifyCredentialResponse.ERROR;
}
+ final CredentialHash storedHash = mStorage.readCredentialHash(userId);
if (storedHash.type != credentialType) {
Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
+ " stored: " + storedHash.type + " passed in: " + credentialType);
@@ -1485,29 +1467,6 @@
return response;
}
- private VerifyCredentialResponse verifyFrpCredential(String credential, int credentialType,
- PersistentData data, ICheckCredentialProgressCallback progressCallback)
- throws RemoteException {
- CredentialHash storedHash = CredentialHash.fromBytes(data.payload);
- if (storedHash.type != credentialType) {
- Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
- + " stored: " + storedHash.type + " passed in: " + credentialType);
- return VerifyCredentialResponse.ERROR;
- }
- if (ArrayUtils.isEmpty(storedHash.hash) || TextUtils.isEmpty(credential)) {
- Slog.e(TAG, "Stored hash or credential is empty");
- return VerifyCredentialResponse.ERROR;
- }
- VerifyCredentialResponse response = VerifyCredentialResponse.fromGateKeeperResponse(
- getGateKeeperService().verifyChallenge(data.userId, 0 /* challenge */,
- storedHash.hash, credential.getBytes()));
- if (progressCallback != null
- && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
- progressCallback.onCredentialVerified();
- }
- return response;
- }
-
@Override
public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
long challenge, int userId) throws RemoteException {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 79372e48..b4c10ec 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -635,9 +635,8 @@
static final int VERSION_1_HEADER_SIZE = 1 + 1 + 4 + 4;
public static final int TYPE_NONE = 0;
- public static final int TYPE_GATEKEEPER = 1;
- public static final int TYPE_SP = 2;
- public static final int TYPE_SP_WEAVER = 3;
+ public static final int TYPE_SP = 1;
+ public static final int TYPE_SP_WEAVER = 2;
public static final PersistentData NONE = new PersistentData(TYPE_NONE,
UserHandle.USER_NULL, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, null);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b6af076..38f1c07 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -18,7 +18,7 @@
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
-import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.MANAGE_FALLBACK_SUBSCRIPTION_PLANS;
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.Manifest.permission.READ_PHONE_STATE;
@@ -28,14 +28,12 @@
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIMAX;
-import static android.net.ConnectivityManager.isNetworkTypeMobile;
-import static android.net.NetworkPolicy.CYCLE_NONE;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -46,20 +44,20 @@
import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
+import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
+import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
-import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
+import static android.net.NetworkPolicyManager.resolveNetworkId;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
@@ -68,16 +66,9 @@
import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.net.wifi.WifiManager.CHANGE_REASON_ADDED;
-import static android.net.wifi.WifiManager.CHANGE_REASON_REMOVED;
-import static android.net.wifi.WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION;
-import static android.net.wifi.WifiManager.EXTRA_CHANGE_REASON;
-import static android.net.wifi.WifiManager.EXTRA_NETWORK_INFO;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_CONFIGURATION;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_INFO;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
-import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
+import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.internal.util.ArrayUtils.appendInt;
@@ -127,15 +118,14 @@
import android.net.INetworkStatsService;
import android.net.LinkProperties;
import android.net.NetworkIdentity;
-import android.net.NetworkInfo;
import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
import android.net.NetworkQuotaInfo;
import android.net.NetworkState;
import android.net.NetworkTemplate;
+import android.net.TrafficStats;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
-import android.os.PowerSaveState;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
@@ -147,18 +137,23 @@
import android.os.PersistableBundle;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
+import android.os.PowerSaveState;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
+import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.format.Formatter;
@@ -190,8 +185,8 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
-
import com.android.server.power.BatterySaverPolicy.ServiceType;
+
import libcore.io.IoUtils;
import com.google.android.collect.Lists;
@@ -210,10 +205,11 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
+import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
import java.util.Calendar;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -756,15 +752,10 @@
mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
MANAGE_NETWORK_POLICY, mHandler);
- // listen for configured wifi networks to be removed
- final IntentFilter wifiConfigFilter =
- new IntentFilter(CONFIGURED_NETWORKS_CHANGED_ACTION);
- mContext.registerReceiver(mWifiConfigReceiver, wifiConfigFilter, null, mHandler);
-
- // listen for wifi state changes to catch metered hint
- final IntentFilter wifiStateFilter = new IntentFilter(
- WifiManager.NETWORK_STATE_CHANGED_ACTION);
- mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
+ // listen for configured wifi networks to be loaded
+ final IntentFilter wifiFilter =
+ new IntentFilter(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
+ mContext.registerReceiver(mWifiReceiver, wifiFilter, null, mHandler);
// listen for carrier config changes to update data cycle information
final IntentFilter carrierConfigFilter = new IntentFilter(
@@ -960,80 +951,22 @@
};
/**
- * Receiver that watches for {@link WifiConfiguration} to be changed.
+ * Receiver that watches for {@link WifiConfiguration} to be loaded so that
+ * we can perform upgrade logic.
*/
- final private BroadcastReceiver mWifiConfigReceiver = new BroadcastReceiver() {
+ final private BroadcastReceiver mWifiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // on background handler thread, and verified CONNECTIVITY_INTERNAL
- // permission above.
-
- final int reason = intent.getIntExtra(EXTRA_CHANGE_REASON, CHANGE_REASON_ADDED);
- if (reason == CHANGE_REASON_REMOVED) {
- final WifiConfiguration config = intent.getParcelableExtra(
- EXTRA_WIFI_CONFIGURATION);
- if (config.SSID != null) {
- final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(config.SSID);
- synchronized (mUidRulesFirstLock) {
- synchronized (mNetworkPoliciesSecondLock) {
- if (mNetworkPolicy.containsKey(template)) {
- mNetworkPolicy.remove(template);
- writePolicyAL();
- }
- }
- }
- }
- }
- }
- };
-
- /**
- * Receiver that watches {@link WifiInfo} state changes to infer metered
- * state. Ignores hints when policy is user-defined.
- */
- final private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // on background handler thread, and verified CONNECTIVITY_INTERNAL
- // permission above.
-
- // ignore when not connected
- final NetworkInfo netInfo = intent.getParcelableExtra(EXTRA_NETWORK_INFO);
- if (!netInfo.isConnected()) return;
-
- final WifiInfo info = intent.getParcelableExtra(EXTRA_WIFI_INFO);
- final boolean meteredHint = info.getMeteredHint();
-
- final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(info.getSSID());
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
- NetworkPolicy policy = mNetworkPolicy.get(template);
- if (policy == null && meteredHint) {
- // policy doesn't exist, and AP is hinting that it's
- // metered: create an inferred policy.
- policy = newWifiPolicy(template, meteredHint);
- addNetworkPolicyAL(policy);
-
- } else if (policy != null && policy.inferred) {
- // policy exists, and was inferred: update its current
- // metered state.
- policy.metered = meteredHint;
-
- // since this is inferred for each wifi session, just update
- // rules without persisting.
- updateNetworkRulesNL();
- }
+ upgradeWifiMeteredOverrideAL();
}
}
+ // Only need to perform upgrade logic once
+ mContext.unregisterReceiver(this);
}
};
- static NetworkPolicy newWifiPolicy(NetworkTemplate template, boolean metered) {
- return new NetworkPolicy(template, CYCLE_NONE, Time.TIMEZONE_UTC,
- WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER,
- metered, true);
- }
-
/**
* Observer that watches for {@link INetworkManagementService} alerts.
*/
@@ -1072,8 +1005,10 @@
if (!isTemplateRelevant(policy.template)) continue;
if (!policy.hasCycle()) continue;
- final long start = computeLastCycleBoundary(currentTime, policy);
- final long end = currentTime;
+ final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
+ .cycleIterator(policy).next();
+ final long start = cycle.first.toInstant().toEpochMilli();
+ final long end = cycle.second.toInstant().toEpochMilli();
final long totalBytes = getTotalBytes(policy.template, start, end);
if (policy.isOverLimit(totalBytes)) {
@@ -1530,8 +1465,10 @@
continue;
}
- final long start = computeLastCycleBoundary(currentTime, policy);
- final long end = currentTime;
+ final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
+ .cycleIterator(policy).next();
+ final long start = cycle.first.toInstant().toEpochMilli();
+ final long end = cycle.second.toInstant().toEpochMilli();
final long totalBytes = getTotalBytes(policy.template, start, end);
// disable data connection when over limit and not snoozed
@@ -1641,15 +1578,11 @@
final NetworkPolicy policy = mNetworkRules.keyAt(i);
final String[] ifaces = mNetworkRules.valueAt(i);
- final long start;
- final long totalBytes;
- if (policy.hasCycle()) {
- start = computeLastCycleBoundary(currentTime, policy);
- totalBytes = getTotalBytes(policy.template, start, currentTime);
- } else {
- start = Long.MAX_VALUE;
- totalBytes = 0;
- }
+ final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
+ .cycleIterator(policy).next();
+ final long start = cycle.first.toInstant().toEpochMilli();
+ final long end = cycle.second.toInstant().toEpochMilli();
+ final long totalBytes = getTotalBytes(policy.template, start, end);
if (LOGD) {
Slog.d(TAG, "applying policy " + policy + " to ifaces " + Arrays.toString(ifaces));
@@ -1905,7 +1838,6 @@
cycleTimezone, warningBytes, limitBytes, lastWarningSnooze,
lastLimitSnooze, metered, inferred));
}
-
} else if (TAG_UID_POLICY.equals(tag)) {
final int uid = readIntAttribute(in, ATTR_UID);
final int policy = readIntAttribute(in, ATTR_POLICY);
@@ -1965,7 +1897,7 @@
} catch (FileNotFoundException e) {
// missing policy is okay, probably first boot
- upgradeLegacyBackgroundDataUL();
+ upgradeDefaultBackgroundDataUL();
} catch (IOException e) {
Log.wtf(TAG, "problem reading network policy", e);
} catch (XmlPullParserException e) {
@@ -1979,15 +1911,55 @@
* Upgrade legacy background data flags, notifying listeners of one last
* change to always-true.
*/
- private void upgradeLegacyBackgroundDataUL() {
- mRestrictBackground = Settings.Secure.getInt(
- mContext.getContentResolver(), Settings.Secure.BACKGROUND_DATA, 1) != 1;
+ private void upgradeDefaultBackgroundDataUL() {
+ // This method is only called when we're unable to find the network policy flag, which
+ // usually happens on first boot of a new device and not one that has received an OTA.
- // kick off one last broadcast if restricted
- if (mRestrictBackground) {
- final Intent broadcast = new Intent(
- ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
- mContext.sendBroadcastAsUser(broadcast, UserHandle.ALL);
+ // Seed from the default value configured for this device.
+ mRestrictBackground = Settings.Global.getInt(
+ mContext.getContentResolver(), Global.DEFAULT_RESTRICT_BACKGROUND_DATA, 0) == 1;
+
+ // NOTE: We used to read the legacy setting here :
+ //
+ // final int legacyFlagValue = Settings.Secure.getInt(
+ // mContext.getContentResolver(), Settings.Secure.BACKGROUND_DATA, ..);
+ //
+ // This is no longer necessary because we will never upgrade directly from Gingerbread
+ // to O+. Devices upgrading from ICS onwards to O will have a netpolicy.xml file that
+ // contains the correct value that we will continue to use.
+ }
+
+ /**
+ * Perform upgrade step of moving any user-defined meterness overrides over
+ * into {@link WifiConfiguration}.
+ */
+ private void upgradeWifiMeteredOverrideAL() {
+ boolean modified = false;
+ final WifiManager wm = mContext.getSystemService(WifiManager.class);
+ final List<WifiConfiguration> configs = wm.getConfiguredNetworks();
+ for (int i = 0; i < mNetworkPolicy.size(); ) {
+ final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
+ if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI
+ && !policy.inferred) {
+ mNetworkPolicy.removeAt(i);
+ modified = true;
+
+ final String networkId = resolveNetworkId(policy.template.getNetworkId());
+ for (WifiConfiguration config : configs) {
+ if (Objects.equals(resolveNetworkId(config), networkId)) {
+ Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint");
+ config.meteredOverride = policy.metered
+ ? WifiConfiguration.METERED_OVERRIDE_METERED
+ : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ wm.updateNetwork(config);
+ }
+ }
+ } else {
+ i++;
+ }
+ }
+ if (modified) {
+ writePolicyAL();
}
}
@@ -2495,81 +2467,202 @@
}
}
- private NetworkPolicy findPolicyForNetworkNL(NetworkIdentity ident) {
- for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
- NetworkPolicy policy = mNetworkPolicy.valueAt(i);
- if (policy.template.matches(ident)) {
- return policy;
- }
- }
- return null;
- }
-
@Override
- public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) {
- mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
-
- // only returns usage summary, so we don't require caller to have
- // READ_NETWORK_USAGE_HISTORY.
+ public void setWifiMeteredOverride(String networkId, int meteredOverride) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
final long token = Binder.clearCallingIdentity();
try {
- return getNetworkQuotaInfoUnchecked(state);
+ final WifiManager wm = mContext.getSystemService(WifiManager.class);
+ final List<WifiConfiguration> configs = wm.getConfiguredNetworks();
+ for (WifiConfiguration config : configs) {
+ if (Objects.equals(resolveNetworkId(config), networkId)) {
+ config.meteredOverride = meteredOverride;
+ wm.updateNetwork(config);
+ }
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
}
- private NetworkQuotaInfo getNetworkQuotaInfoUnchecked(NetworkState state) {
- final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
+ @Override
+ @Deprecated
+ public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) {
+ Log.w(TAG, "Shame on UID " + Binder.getCallingUid()
+ + " for calling the hidden API getNetworkQuotaInfo(). Shame!");
+ return new NetworkQuotaInfo();
+ }
- final NetworkPolicy policy;
- synchronized (mNetworkPoliciesSecondLock) {
- policy = findPolicyForNetworkNL(ident);
+ private void enforceSubscriptionPlanAccess(int subId, int callingUid, String callingPackage) {
+ // Verify they're not lying about package name
+ mAppOps.checkPackage(callingUid, callingPackage);
+
+ // Verify they have phone permission from user
+ mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
+ if (mAppOps.checkOp(AppOpsManager.OP_READ_PHONE_STATE, callingUid,
+ callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ throw new SecurityException(
+ "Calling package " + callingPackage + " does not hold " + READ_PHONE_STATE);
}
- if (policy == null || !policy.hasCycle()) {
- // missing policy means we can't derive useful quota info
- return null;
+ final SubscriptionInfo si;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ si = mContext.getSystemService(SubscriptionManager.class)
+ .getActiveSubscriptionInfo(subId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- final long currentTime = currentTimeMillis();
+ // First check: does caller have carrier access?
+ if (si.isEmbedded() && si.canManageSubscription(mContext, callingPackage)) {
+ Slog.v(TAG, "Granting access because " + callingPackage + " is carrier");
+ return;
+ }
- // find total bytes used under policy
- final long start = computeLastCycleBoundary(currentTime, policy);
- final long end = currentTime;
- final long totalBytes = getTotalBytes(policy.template, start, end);
+ // Second check: was caller first to claim this HNI?
+ // TODO: extend to support external data sources
- // report soft and hard limits under policy
- final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes
- : NetworkQuotaInfo.NO_LIMIT;
- final long hardLimitBytes = policy.limitBytes != LIMIT_DISABLED ? policy.limitBytes
- : NetworkQuotaInfo.NO_LIMIT;
+ // Final check: does caller have fallback permission?
+ if (mContext.checkCallingOrSelfPermission(
+ MANAGE_FALLBACK_SUBSCRIPTION_PLANS) == PERMISSION_GRANTED) {
+ Slog.v(TAG, "Granting access because " + callingPackage + " is fallback");
+ return;
+ }
- return new NetworkQuotaInfo(totalBytes, softLimitBytes, hardLimitBytes);
+ throw new SecurityException("Calling package " + callingPackage
+ + " has no access to subscription plans for " + subId);
}
@Override
- public boolean isNetworkMetered(NetworkState state) {
- if (state.networkInfo == null) {
- return false;
+ public SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage) {
+ enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
+
+ // TODO: extend to support external data sources
+ if (!"com.android.settings".equals(callingPackage)) {
+ throw new UnsupportedOperationException();
}
- final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
-
- final NetworkPolicy policy;
- synchronized (mNetworkPoliciesSecondLock) {
- policy = findPolicyForNetworkNL(ident);
- }
-
- if (policy != null) {
- return policy.metered;
- } else {
- final int type = state.networkInfo.getType();
- if ((isNetworkTypeMobile(type) && ident.getMetered()) || type == TYPE_WIMAX) {
- return true;
+ final String fake = SystemProperties.get("fw.fake_plan");
+ if (!TextUtils.isEmpty(fake)) {
+ final List<SubscriptionPlan> plans = new ArrayList<>();
+ if ("month_hard".equals(fake)) {
+ plans.add(SubscriptionPlan.Builder
+ .createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"))
+ .setTitle("G-Mobile")
+ .setDataWarning(2 * TrafficStats.GB_IN_BYTES)
+ .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+ SubscriptionPlan.LIMIT_BEHAVIOR_BILLED)
+ .setDataUsage(1 * TrafficStats.GB_IN_BYTES,
+ ZonedDateTime.now().minusHours(36).toInstant().toEpochMilli())
+ .build());
+ } else if ("month_soft".equals(fake)) {
+ plans.add(SubscriptionPlan.Builder
+ .createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"))
+ .setTitle("G-Mobile is the carriers name who this plan belongs to")
+ .setSummary("Crazy unlimited bandwidth plan with incredibly long title "
+ + "that should be cut off to prevent UI from looking terrible")
+ .setDataWarning(2 * TrafficStats.GB_IN_BYTES)
+ .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+ SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
+ .setDataUsage(1 * TrafficStats.GB_IN_BYTES,
+ ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
+ .build());
+ } else if ("month_none".equals(fake)) {
+ plans.add(SubscriptionPlan.Builder
+ .createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"))
+ .setTitle("G-Mobile")
+ .build());
+ } else if ("prepaid".equals(fake)) {
+ plans.add(SubscriptionPlan.Builder
+ .createNonrecurring(ZonedDateTime.now().minusDays(20),
+ ZonedDateTime.now().plusDays(10))
+ .setTitle("G-Mobile")
+ .setDataLimit(512 * TrafficStats.MB_IN_BYTES,
+ SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
+ .setDataUsage(100 * TrafficStats.MB_IN_BYTES,
+ ZonedDateTime.now().minusHours(3).toInstant().toEpochMilli())
+ .build());
+ } else if ("prepaid_crazy".equals(fake)) {
+ plans.add(SubscriptionPlan.Builder
+ .createNonrecurring(ZonedDateTime.now().minusDays(20),
+ ZonedDateTime.now().plusDays(10))
+ .setTitle("G-Mobile Anytime")
+ .setDataLimit(512 * TrafficStats.MB_IN_BYTES,
+ SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
+ .setDataUsage(100 * TrafficStats.MB_IN_BYTES,
+ ZonedDateTime.now().minusHours(3).toInstant().toEpochMilli())
+ .build());
+ plans.add(SubscriptionPlan.Builder
+ .createNonrecurring(ZonedDateTime.now().minusDays(10),
+ ZonedDateTime.now().plusDays(20))
+ .setTitle("G-Mobile Nickel Nights")
+ .setSummary("5¢/GB between 1-5AM")
+ .setDataUsage(15 * TrafficStats.MB_IN_BYTES,
+ ZonedDateTime.now().minusHours(30).toInstant().toEpochMilli())
+ .build());
+ plans.add(SubscriptionPlan.Builder
+ .createNonrecurring(ZonedDateTime.now().minusDays(10),
+ ZonedDateTime.now().plusDays(20))
+ .setTitle("G-Mobile Bonus 3G")
+ .setSummary("Unlimited 3G data")
+ .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+ SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
+ .setDataUsage(300 * TrafficStats.MB_IN_BYTES,
+ ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
+ .build());
}
- return false;
+ return plans.toArray(new SubscriptionPlan[plans.size()]);
}
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ final NetworkTemplate template = NetworkTemplate
+ .buildTemplateMobileAll(tm.getSubscriberId(subId));
+ final NetworkPolicy policy = mNetworkPolicy.get(template);
+ if (policy != null) {
+ return new SubscriptionPlan[] { SubscriptionPlan.convert(policy) };
+ } else {
+ return new SubscriptionPlan[0];
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage) {
+ enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
+
+ // TODO: extend to support external data sources
+ if (!"com.android.settings".equals(callingPackage)) {
+ throw new UnsupportedOperationException();
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ final NetworkTemplate template = NetworkTemplate
+ .buildTemplateMobileAll(tm.getSubscriberId(subId));
+ if (ArrayUtils.isEmpty(plans)) {
+ mNetworkPolicy.remove(template);
+ } else {
+ final NetworkPolicy policy = SubscriptionPlan.convert(plans[0]);
+ policy.template = template;
+ mNetworkPolicy.put(template, policy);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public String getSubscriptionPlanOwner(int subId) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // TODO: extend to support external data sources
+ return "com.android.settings";
}
@Override
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index 8ced1c2..b65b9d7 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -19,26 +19,17 @@
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
-import static android.net.wifi.WifiInfo.removeDoubleQuotes;
-
-import static com.android.server.net.NetworkPolicyManagerService.newWifiPolicy;
-import static com.android.server.net.NetworkPolicyManagerService.TAG;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
import android.content.Context;
import android.net.INetworkPolicyManager;
-import android.net.NetworkPolicy;
-import android.net.NetworkTemplate;
+import android.net.NetworkPolicyManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.RemoteException;
import android.os.ShellCommand;
-import android.util.Log;
+
+import java.io.PrintWriter;
+import java.util.List;
class NetworkPolicyManagerShellCommand extends ShellCommand {
@@ -90,7 +81,7 @@
pw.println(" Adds a UID to the blacklist for restrict background usage.");
pw.println(" get restrict-background");
pw.println(" Gets the global restrict background usage status.");
- pw.println(" list wifi-networks [BOOLEAN]");
+ pw.println(" list wifi-networks [true|false]");
pw.println(" Lists all saved wifi networks and whether they are metered or not.");
pw.println(" If a boolean argument is passed, filters just the metered (or unmetered)");
pw.println(" networks.");
@@ -102,7 +93,7 @@
pw.println(" Removes a UID from the whitelist for restrict background usage.");
pw.println(" remove restrict-background-blacklist UID");
pw.println(" Removes a UID from the blacklist for restrict background usage.");
- pw.println(" set metered-network ID BOOLEAN");
+ pw.println(" set metered-network ID [undefined|true|false]");
pw.println(" Toggles whether the given wi-fi network is metered.");
pw.println(" set restrict-background BOOLEAN");
pw.println(" Sets the global restrict background usage status.");
@@ -276,107 +267,60 @@
return resetUidPolicy("not blacklisted", POLICY_REJECT_METERED_BACKGROUND);
}
- private int listWifiNetworks() throws RemoteException {
+ private int listWifiNetworks() {
final PrintWriter pw = getOutPrintWriter();
final String arg = getNextArg();
- final Boolean filter = arg == null ? null : Boolean.valueOf(arg);
- for (NetworkPolicy policy : getWifiPolicies()) {
- if (filter != null && filter.booleanValue() != policy.metered) {
- continue;
+ final int match;
+ if (arg == null) {
+ match = WifiConfiguration.METERED_OVERRIDE_NONE;
+ } else if (Boolean.parseBoolean(arg)) {
+ match = WifiConfiguration.METERED_OVERRIDE_METERED;
+ } else {
+ match = WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ }
+
+ final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+ for (WifiConfiguration config : configs) {
+ if (arg == null || config.meteredOverride == match) {
+ pw.print(NetworkPolicyManager.resolveNetworkId(config));
+ pw.print(';');
+ pw.println(overrideToString(config.meteredOverride));
}
- pw.print(getNetworkId(policy));
- pw.print(';');
- pw.println(policy.metered);
}
return 0;
}
private int setMeteredWifiNetwork() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
- final String id = getNextArg();
- if (id == null) {
- pw.println("Error: didn't specify ID");
+ final String networkId = getNextArg();
+ if (networkId == null) {
+ pw.println("Error: didn't specify networkId");
return -1;
}
final String arg = getNextArg();
if (arg == null) {
- pw.println("Error: didn't specify BOOLEAN");
+ pw.println("Error: didn't specify meteredOverride");
return -1;
}
- final boolean metered = Boolean.valueOf(arg);
- final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null);
- boolean changed = false;
- // First try to find a policy with such id
- for (NetworkPolicy policy : policies) {
- if (policy.template.isMatchRuleMobile() || policy.metered == metered) {
- continue;
- }
- final String networkId = getNetworkId(policy);
- if (id.equals(networkId)) {
- Log.i(TAG, "Changing " + networkId + " metered status to " + metered);
- policy.metered = metered;
- changed = true;
- }
- }
- if (changed) {
- mInterface.setNetworkPolicies(policies);
- return 0;
- }
- // Policy not found: check if there is a saved wi-fi with such id.
- for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) {
- final String ssid = removeDoubleQuotes(config.SSID);
- if (id.equals(ssid)) {
- final NetworkPolicy policy = newPolicy(ssid);
- policy.metered = true;
- Log.i(TAG, "Creating new policy for " + ssid + ": " + policy);
- final NetworkPolicy[] newPolicies = new NetworkPolicy[policies.length + 1];
- System.arraycopy(policies, 0, newPolicies, 0, policies.length);
- newPolicies[newPolicies.length - 1] = policy;
- mInterface.setNetworkPolicies(newPolicies);
- return 0;
- }
- }
- pw.print("Error: didn't find network with SSID "); pw.println(id);
+ mInterface.setWifiMeteredOverride(NetworkPolicyManager.resolveNetworkId(networkId),
+ stringToOverride(arg));
return -1;
}
- private List<NetworkPolicy> getWifiPolicies() throws RemoteException {
- // First gets a list of saved wi-fi networks.
- final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
- final int size = configs != null ? configs.size() : 0;
- final Set<String> ssids = new HashSet<>(size);
- if (configs != null) {
- for (WifiConfiguration config : configs) {
- ssids.add(removeDoubleQuotes(config.SSID));
- }
+ private static String overrideToString(int override) {
+ switch (override) {
+ case WifiConfiguration.METERED_OVERRIDE_METERED: return "true";
+ case WifiConfiguration.METERED_OVERRIDE_NOT_METERED: return "false";
+ default: return "none";
}
-
- // Then gets the saved policies.
- final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null);
- final List<NetworkPolicy> wifiPolicies = new ArrayList<NetworkPolicy>(policies.length);
- for (NetworkPolicy policy: policies) {
- if (!policy.template.isMatchRuleMobile()) {
- wifiPolicies.add(policy);
- final String netId = getNetworkId(policy);
- ssids.remove(netId);
- }
- }
- // Finally, creates new default policies for saved WI-FIs not policied yet.
- for (String ssid : ssids) {
- final NetworkPolicy policy = newPolicy(ssid);
- wifiPolicies.add(policy);
- }
- return wifiPolicies;
}
- private NetworkPolicy newPolicy(String ssid) {
- final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(ssid);
- final NetworkPolicy policy = newWifiPolicy(template, false);
- return policy;
- }
-
- private String getNetworkId(NetworkPolicy policy) {
- return removeDoubleQuotes(policy.template.getNetworkId());
+ private static int stringToOverride(String override) {
+ switch (override) {
+ case "true": return WifiConfiguration.METERED_OVERRIDE_METERED;
+ case "false": return WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ default: return WifiConfiguration.METERED_OVERRIDE_NONE;
+ }
}
private int getNextBooleanArg() {
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index 1bd2085..184f8b2 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -47,9 +47,11 @@
if (!userWantsBadges || !appCanShowBadge) {
record.setShowBadge(false);
} else {
- record.setShowBadge(mConfig.getNotificationChannel(record.sbn.getPackageName(),
- record.sbn.getUid(), record.getChannel().getId(), false).canShowBadge()
- && appCanShowBadge);
+ if (record.getChannel() != null) {
+ record.setShowBadge(record.getChannel().canShowBadge() && appCanShowBadge);
+ } else {
+ record.setShowBadge(appCanShowBadge);
+ }
}
return null;
diff --git a/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java b/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java
new file mode 100644
index 0000000..7c82845
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java
@@ -0,0 +1,48 @@
+/**
+* Copyright (C) 2017 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.notification;
+
+import android.content.Context;
+import android.util.Slog;
+
+/**
+ * Applies adjustments from the group helper and notification assistant
+ */
+public class NotificationAdjustmentExtractor implements NotificationSignalExtractor {
+ private static final String TAG = "BadgeExtractor";
+ private static final boolean DBG = false;
+
+
+ public void initialize(Context ctx, NotificationUsageStats usageStats) {
+ if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
+ }
+
+ public RankingReconsideration process(NotificationRecord record) {
+ if (record == null || record.getNotification() == null) {
+ if (DBG) Slog.d(TAG, "skipping empty notification");
+ return null;
+ }
+
+ record.applyAdjustments();
+
+ return null;
+ }
+
+ @Override
+ public void setConfig(RankingConfig config) {
+ // config is not used
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationChannelExtractor.java b/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
new file mode 100644
index 0000000..46ab556
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationChannelExtractor.java
@@ -0,0 +1,55 @@
+/**
+* Copyright (C) 2017 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.notification;
+
+import android.content.Context;
+import android.util.Slog;
+
+/**
+ * Stores the latest notification channel information for this notification
+ */
+public class NotificationChannelExtractor implements NotificationSignalExtractor {
+ private static final String TAG = "BadgeExtractor";
+ private static final boolean DBG = false;
+
+ private RankingConfig mConfig;
+
+ public void initialize(Context ctx, NotificationUsageStats usageStats) {
+ if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
+ }
+
+ public RankingReconsideration process(NotificationRecord record) {
+ if (record == null || record.getNotification() == null) {
+ if (DBG) Slog.d(TAG, "skipping empty notification");
+ return null;
+ }
+
+ if (mConfig == null) {
+ if (DBG) Slog.d(TAG, "missing config");
+ return null;
+ }
+
+ record.updateNotificationChannel(mConfig.getNotificationChannel(record.sbn.getPackageName(),
+ record.sbn.getUid(), record.getChannel().getId(), false));
+
+ return null;
+ }
+
+ @Override
+ public void setConfig(RankingConfig config) {
+ mConfig = config;
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
index 4981d5c..12b29cf 100644
--- a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
@@ -58,6 +58,10 @@
}
}
+ if (!record.isRecentlyIntrusive()) {
+ return null;
+ }
+
return new RankingReconsideration(record.getKey(), HANG_TIME_MS) {
@Override
public void work() {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 98a2479..c816e7f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -278,7 +278,7 @@
private ICompanionDeviceManager mCompanionManager;
final IBinder mForegroundToken = new Binder();
- private Handler mHandler;
+ private WorkerHandler mHandler;
private final HandlerThread mRankingThread = new HandlerThread("ranker",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -295,8 +295,8 @@
private String mVibrateNotificationKey;
private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
- new SparseArray<ArraySet<ManagedServiceInfo>>();
- private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
+ new SparseArray<>();
+ private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
private int mListenerHints; // right now, all hints are global
private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
@@ -312,16 +312,14 @@
// used as a mutex for access to all active notifications & listeners
final Object mNotificationLock = new Object();
@GuardedBy("mNotificationLock")
- final ArrayList<NotificationRecord> mNotificationList =
- new ArrayList<NotificationRecord>();
+ final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
@GuardedBy("mNotificationLock")
- final ArrayMap<String, NotificationRecord> mNotificationsByKey =
- new ArrayMap<String, NotificationRecord>();
+ final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
@GuardedBy("mNotificationLock")
final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
@GuardedBy("mNotificationLock")
final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
- final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
+ final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
// The last key in this list owns the hardware.
@@ -1093,7 +1091,7 @@
count--;
}
if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
- count --;
+ count--;
}
}
@@ -1101,6 +1099,13 @@
}
}
+ void clearNotifications() {
+ mEnqueuedNotifications.clear();
+ mNotificationList.clear();
+ mNotificationsByKey.clear();
+ mSummaryByGroupKey.clear();
+ }
+
@VisibleForTesting
void addNotification(NotificationRecord r) {
mNotificationList.add(r);
@@ -1121,7 +1126,7 @@
}
@VisibleForTesting
- void setHandler(Handler handler) {
+ void setHandler(WorkerHandler handler) {
mHandler = handler;
}
@@ -1141,6 +1146,11 @@
}
@VisibleForTesting
+ void setRankingHandler(RankingHandler rankingHandler) {
+ mRankingHandler = rankingHandler;
+ }
+
+ @VisibleForTesting
void setIsTelevision(boolean isTelevision) {
mIsTelevision = isTelevision;
}
@@ -1152,7 +1162,8 @@
// TODO: Tests should call onStart instead once the methods above are removed.
@VisibleForTesting
- void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
+ void init(Looper looper, IPackageManager packageManager,
+ PackageManager packageManagerClient,
LightsManager lightsManager, NotificationListeners notificationListeners,
NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
@@ -1323,7 +1334,8 @@
final File systemDir = new File(Environment.getDataDirectory(), "system");
- init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
+ init(Looper.myLooper(),
+ AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class),
new NotificationListeners(AppGlobals.getPackageManager()),
new NotificationAssistants(AppGlobals.getPackageManager()),
@@ -1343,7 +1355,6 @@
synchronized (mNotificationLock) {
addAutogroupKeyLocked(key);
}
- mRankingHandler.requestSort(false);
}
@Override
@@ -1351,7 +1362,6 @@
synchronized (mNotificationLock) {
removeAutogroupKeyLocked(key);
}
- mRankingHandler.requestSort(false);
}
@Override
@@ -1424,28 +1434,14 @@
}
mRankingHelper.updateNotificationChannel(pkg, uid, channel);
- final NotificationChannel modifiedChannel =
- mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
-
if (!fromListener) {
+ final NotificationChannel modifiedChannel =
+ mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
mListeners.notifyNotificationChannelChanged(
pkg, UserHandle.getUserHandleForUid(uid),
modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
}
- synchronized (mNotificationLock) {
- final int N = mNotificationList.size();
- for (int i = N - 1; i >= 0; --i) {
- NotificationRecord r = mNotificationList.get(i);
- if (r.sbn.getPackageName().equals(pkg)
- && r.sbn.getUid() == uid
- && channel.getId() != null
- && channel.getId().equals(r.getChannel().getId())) {
- r.updateNotificationChannel(modifiedChannel);
- }
- }
- }
- mRankingHandler.requestSort(true);
savePolicyFile();
}
@@ -2883,7 +2879,7 @@
NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
applyAdjustment(n, adjustment);
}
- mRankingHandler.requestSort(true);
+ mRankingHandler.requestSort();
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -2902,7 +2898,7 @@
applyAdjustment(n, adjustment);
}
}
- mRankingHandler.requestSort(true);
+ mRankingHandler.requestSort();
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -2976,39 +2972,44 @@
}
};
- private void applyAdjustment(NotificationRecord n, Adjustment adjustment) {
- if (n == null) {
+ private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
+ if (r == null) {
return;
}
if (adjustment.getSignals() != null) {
Bundle.setDefusable(adjustment.getSignals(), true);
- final ArrayList<String> people =
- adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
- final ArrayList<SnoozeCriterion> snoozeCriterionList =
- adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA);
- n.setPeopleOverride(people);
- n.setSnoozeCriteria(snoozeCriterionList);
+ r.addAdjustment(adjustment);
}
}
@GuardedBy("mNotificationLock")
- private void addAutogroupKeyLocked(String key) {
- NotificationRecord n = mNotificationsByKey.get(key);
- if (n == null) {
+ void addAutogroupKeyLocked(String key) {
+ NotificationRecord r = mNotificationsByKey.get(key);
+ if (r == null) {
return;
}
- n.setOverrideGroupKey(GroupHelper.AUTOGROUP_KEY);
+ addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
EventLogTags.writeNotificationAutogrouped(key);
+ mRankingHandler.requestSort();
}
@GuardedBy("mNotificationLock")
- private void removeAutogroupKeyLocked(String key) {
- NotificationRecord n = mNotificationsByKey.get(key);
- if (n == null) {
+ void removeAutogroupKeyLocked(String key) {
+ NotificationRecord r = mNotificationsByKey.get(key);
+ if (r == null) {
return;
}
- n.setOverrideGroupKey(null);
+ addAutoGroupAdjustment(r, null);
EventLogTags.writeNotificationUnautogrouped(key);
+ mRankingHandler.requestSort();
+ }
+
+ private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
+ Bundle signals = new Bundle();
+ signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
+ Adjustment adjustment =
+ new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
+ r.addAdjustment(adjustment);
}
// Clears the 'fake' auto-group summary.
@@ -4267,39 +4268,44 @@
}
}
if (changed) {
- scheduleSendRankingUpdate();
+ mHandler.scheduleSendRankingUpdate();
}
}
- private void handleRankingSort(Message msg) {
- if (!(msg.obj instanceof Boolean)) return;
+ void handleRankingSort() {
if (mRankingHelper == null) return;
- boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
synchronized (mNotificationLock) {
final int N = mNotificationList.size();
- // Any field that can change via one of the extractors or by the assistant
- // needs to be added here.
- ArrayList<String> orderBefore = new ArrayList<String>(N);
- ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
+ // Any field that can change via one of the extractors needs to be added here.
+ ArrayList<String> orderBefore = new ArrayList<>(N);
int[] visibilities = new int[N];
boolean[] showBadges = new boolean[N];
+ ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
+ ArrayList<String> groupKeyBefore = new ArrayList<>(N);
+ ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
+ ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
final NotificationRecord r = mNotificationList.get(i);
orderBefore.add(r.getKey());
- groupOverrideBefore.add(r.sbn.getGroupKey());
visibilities[i] = r.getPackageVisibilityOverride();
showBadges[i] = r.canShowBadge();
+ channelBefore.add(r.getChannel());
+ groupKeyBefore.add(r.getGroupKey());
+ overridePeopleBefore.add(r.getPeopleOverride());
+ snoozeCriteriaBefore.add(r.getSnoozeCriteria());
mRankingHelper.extractSignals(r);
}
mRankingHelper.sort(mNotificationList);
for (int i = 0; i < N; i++) {
final NotificationRecord r = mNotificationList.get(i);
- if (forceUpdate
- || !orderBefore.get(i).equals(r.getKey())
+ if (!orderBefore.get(i).equals(r.getKey())
|| visibilities[i] != r.getPackageVisibilityOverride()
- || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())
- || showBadges[i] != r.canShowBadge()) {
- scheduleSendRankingUpdate();
+ || showBadges[i] != r.canShowBadge()
+ || !Objects.equals(channelBefore.get(i), r.getChannel())
+ || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
+ || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
+ || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())) {
+ mHandler.scheduleSendRankingUpdate();
return;
}
}
@@ -4333,13 +4339,6 @@
return mRankingHelper.indexOf(mNotificationList, target);
}
- private void scheduleSendRankingUpdate() {
- if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
- Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
- mHandler.sendMessage(m);
- }
- }
-
private void handleSendRankingUpdate() {
synchronized (mNotificationLock) {
mListeners.notifyRankingUpdateLocked();
@@ -4371,7 +4370,7 @@
}
}
- private final class WorkerHandler extends Handler
+ protected class WorkerHandler extends Handler
{
public WorkerHandler(Looper looper) {
super(looper);
@@ -4400,6 +4399,13 @@
}
}
+ protected void scheduleSendRankingUpdate() {
+ if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
+ Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
+ sendMessage(m);
+ }
+ }
+
}
private final class RankingHandlerWorker extends Handler implements RankingHandler
@@ -4415,16 +4421,15 @@
handleRankingReconsideration(msg);
break;
case MESSAGE_RANKING_SORT:
- handleRankingSort(msg);
+ handleRankingSort();
break;
}
}
- public void requestSort(boolean forceUpdate) {
+ public void requestSort() {
removeMessages(MESSAGE_RANKING_SORT);
Message msg = Message.obtain();
msg.what = MESSAGE_RANKING_SORT;
- msg.obj = forceUpdate;
sendMessage(msg);
}
@@ -5741,11 +5746,16 @@
public static final String USAGE = "help\n"
+ "allow_listener COMPONENT\n"
+ "disallow_listener COMPONENT\n"
+ + "set_assistant COMPONENT\n"
+ + "remove_assistant COMPONENT\n"
+ "allow_dnd PACKAGE\n"
+ "disallow_dnd PACKAGE";
@Override
public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
final PrintWriter pw = getOutPrintWriter();
try {
switch (cmd) {
@@ -5778,6 +5788,24 @@
getBinderService().setNotificationListenerAccessGranted(cn, false);
}
break;
+ case "allow_assistant": {
+ ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
+ if (cn == null) {
+ pw.println("Invalid assistant - must be a ComponentName");
+ return -1;
+ }
+ getBinderService().setNotificationAssistantAccessGranted(cn, true);
+ }
+ break;
+ case "disallow_assistant": {
+ ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
+ if (cn == null) {
+ pw.println("Invalid assistant - must be a ComponentName");
+ return -1;
+ }
+ getBinderService().setNotificationAssistantAccessGranted(cn, false);
+ }
+ break;
default:
return handleDefaultCommands(cmd);
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 1dee71c..77bf9e3 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -35,8 +35,10 @@
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Build;
+import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.notification.Adjustment;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRecordProto;
import android.service.notification.SnoozeCriterion;
@@ -57,6 +59,7 @@
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -132,6 +135,8 @@
private String mGroupLogTag;
private String mChannelIdLogTag;
+ private final List<Adjustment> mAdjustments;
+
@VisibleForTesting
public NotificationRecord(Context context, StatusBarNotification sbn,
NotificationChannel channel)
@@ -150,6 +155,7 @@
mAttributes = calculateAttributes();
mImportance = calculateImportance();
mLight = calculateLights();
+ mAdjustments = new ArrayList<>();
}
private boolean isPreChannelsNotification() {
@@ -504,6 +510,7 @@
if (getSnoozeCriteria() != null) {
pw.println(prefix + "snoozeCriteria=" + TextUtils.join(",", getSnoozeCriteria()));
}
+ pw.println(prefix + "mAdjustments=" + mAdjustments);
}
@@ -539,6 +546,36 @@
this.sbn.getNotification());
}
+ public void addAdjustment(Adjustment adjustment) {
+ synchronized (mAdjustments) {
+ mAdjustments.add(adjustment);
+ }
+ }
+
+ public void applyAdjustments() {
+ synchronized (mAdjustments) {
+ for (Adjustment adjustment: mAdjustments) {
+ Bundle signals = adjustment.getSignals();
+ if (signals.containsKey(Adjustment.KEY_PEOPLE)) {
+ final ArrayList<String> people =
+ adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
+ setPeopleOverride(people);
+ }
+ if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
+ final ArrayList<SnoozeCriterion> snoozeCriterionList =
+ adjustment.getSignals().getParcelableArrayList(
+ Adjustment.KEY_SNOOZE_CRITERIA);
+ setSnoozeCriteria(snoozeCriterionList);
+ }
+ if (signals.containsKey(Adjustment.KEY_GROUP_KEY)) {
+ final String groupOverrideKey =
+ adjustment.getSignals().getString(Adjustment.KEY_GROUP_KEY);
+ setOverrideGroupKey(groupOverrideKey);
+ }
+ }
+ }
+ }
+
public void setContactAffinity(float contactAffinity) {
mContactAffinity = contactAffinity;
if (mImportance < IMPORTANCE_DEFAULT &&
diff --git a/services/core/java/com/android/server/notification/RankingHandler.java b/services/core/java/com/android/server/notification/RankingHandler.java
index 656d727..96324d8 100644
--- a/services/core/java/com/android/server/notification/RankingHandler.java
+++ b/services/core/java/com/android/server/notification/RankingHandler.java
@@ -16,6 +16,6 @@
package com.android.server.notification;
public interface RankingHandler {
- public void requestSort(boolean forceUpdate);
+ public void requestSort();
public void requestReconsideration(RankingReconsideration recon);
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 108a41d..5c2c2b3 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -399,7 +399,7 @@
for (int i = 0; i < N; i++) {
mSignalExtractors[i].setConfig(this);
}
- mRankingHandler.requestSort(false);
+ mRankingHandler.requestSort();
}
public void sort(ArrayList<NotificationRecord> notificationList) {
@@ -511,7 +511,6 @@
MetricsLogger.action(getChannelGroupLog(group.getId(), pkg));
}
r.groups.put(group.getId(), group);
- updateConfig();
}
@Override
@@ -569,7 +568,6 @@
r.channels.put(channel.getId(), channel);
MetricsLogger.action(getChannelLog(channel, pkg).setType(
MetricsProto.MetricsEvent.TYPE_OPEN));
- updateConfig();
}
void clearLockedFields(NotificationChannel channel) {
@@ -641,7 +639,6 @@
LogMaker lm = getChannelLog(channel, pkg);
lm.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
MetricsLogger.action(lm);
- updateConfig();
}
}
@@ -655,7 +652,6 @@
return;
}
r.channels.remove(channelId);
- updateConfig();
}
@Override
@@ -672,7 +668,6 @@
r.channels.remove(key);
}
}
- updateConfig();
}
public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg,
@@ -735,7 +730,6 @@
deletedChannels.add(nc);
}
}
- updateConfig();
return deletedChannels;
}
@@ -1150,7 +1144,7 @@
changed |= oldValue != newValue;
}
if (changed) {
- mRankingHandler.requestSort(false);
+ mRankingHandler.requestSort();
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index cbaad46..a7a2743 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -104,9 +104,6 @@
}
public boolean shouldIntercept(int zen, ZenModeConfig config, NotificationRecord record) {
- if (isSystem(record)) {
- return false;
- }
switch (zen) {
case Global.ZEN_MODE_NO_INTERRUPTIONS:
// #notevenalarms
@@ -177,10 +174,6 @@
return false;
}
- private static boolean isSystem(NotificationRecord record) {
- return record.isCategory(Notification.CATEGORY_SYSTEM);
- }
-
private static boolean isAlarm(NotificationRecord record) {
return record.isCategory(Notification.CATEGORY_ALARM)
|| record.isAudioStream(AudioManager.STREAM_ALARM)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 700d3c2..c3a40bf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2699,7 +2699,16 @@
// Remove any shared userIDs that have no associated packages
mSettings.pruneSharedUsersLPw();
-
+ final long systemScanTime = SystemClock.uptimeMillis() - startTime;
+ final int systemPackagesCount = mPackages.size();
+ Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
+ + " ms, packageCount: " + systemPackagesCount
+ + " ms, timePerPackage: "
+ + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount));
+ if (mIsUpgrade && systemPackagesCount > 0) {
+ MetricsLogger.histogram(null, "ota_package_manager_system_app_avg_scan_time",
+ ((int) systemScanTime) / systemPackagesCount);
+ }
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
@@ -2780,6 +2789,16 @@
}
}
}
+ final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
+ final int dataPackagesCount = mPackages.size() - systemPackagesCount;
+ Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+ + " ms, packageCount: " + dataPackagesCount
+ + " ms, timePerPackage: "
+ + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount));
+ if (mIsUpgrade && dataPackagesCount > 0) {
+ MetricsLogger.histogram(null, "ota_package_manager_data_app_avg_scan_time",
+ ((int) dataScanTime) / dataPackagesCount);
+ }
}
mExpectingBetter.clear();
@@ -3009,6 +3028,10 @@
userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
}
mDexManager.load(userPackages);
+ if (mIsUpgrade) {
+ MetricsLogger.histogram(null, "ota_package_manager_init_time",
+ (int) (SystemClock.uptimeMillis() - startTime));
+ }
} // synchronized (mPackages)
} // synchronized (mInstallLock)
diff --git a/services/core/java/com/android/server/timezone/PackageStatusStorage.java b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
index fe82dc4..cac7f7b 100644
--- a/services/core/java/com/android/server/timezone/PackageStatusStorage.java
+++ b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
@@ -16,6 +16,7 @@
package com.android.server.timezone;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FastXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
@@ -80,7 +81,7 @@
private final AtomicFile mPackageStatusFile;
PackageStatusStorage(File storageDir) {
- mPackageStatusFile = new AtomicFile(new File(storageDir, "packageStatus.xml"));
+ mPackageStatusFile = new AtomicFile(new File(storageDir, "package-status.xml"));
if (!mPackageStatusFile.getBaseFile().exists()) {
try {
insertInitialPackageStatus();
@@ -103,7 +104,7 @@
PackageStatus getPackageStatus() {
synchronized (this) {
try {
- return getPackageStatusInternal();
+ return getPackageStatusLocked();
} catch (ParseException e) {
// This means that data exists in the file but it was bad.
Slog.e(LOG_TAG, "Package status invalid, resetting and retrying", e);
@@ -111,7 +112,7 @@
// Reset the storage so it is in a good state again.
recoverFromBadData(e);
try {
- return getPackageStatusInternal();
+ return getPackageStatusLocked();
} catch (ParseException e2) {
throw new IllegalStateException("Recovery from bad file failed", e2);
}
@@ -119,7 +120,8 @@
}
}
- private PackageStatus getPackageStatusInternal() throws ParseException {
+ @GuardedBy("this")
+ private PackageStatus getPackageStatusLocked() throws ParseException {
try (FileInputStream fis = mPackageStatusFile.openRead()) {
XmlPullParser parser = parseToPackageStatusTag(fis);
Integer checkStatus = getNullableIntAttribute(parser, ATTRIBUTE_CHECK_STATUS);
@@ -137,7 +139,7 @@
}
}
- // Callers should be synchronized(this).
+ @GuardedBy("this")
private int recoverFromBadData(Exception cause) {
mPackageStatusFile.delete();
try {
@@ -155,7 +157,7 @@
// is reset to ensure that old tokens are unlikely to work.
final int initialOptimisticLockId = (int) System.currentTimeMillis();
- writePackageStatusInternal(null /* status */, initialOptimisticLockId,
+ writePackageStatusLocked(null /* status */, initialOptimisticLockId,
null /* packageVersions */);
return initialOptimisticLockId;
}
@@ -243,7 +245,7 @@
}
}
- // Caller should be synchronized(this).
+ @GuardedBy("this")
private int getCurrentOptimisticLockId() throws ParseException {
try (FileInputStream fis = mPackageStatusFile.openRead()) {
XmlPullParser parser = parseToPackageStatusTag(fis);
@@ -278,7 +280,7 @@
}
}
- // Caller should be synchronized(this).
+ @GuardedBy("this")
private boolean writePackageStatusWithOptimisticLockCheck(int optimisticLockId,
int newOptimisticLockId, Integer status, PackageVersions packageVersions)
throws IOException {
@@ -294,12 +296,12 @@
return false;
}
- writePackageStatusInternal(status, newOptimisticLockId, packageVersions);
+ writePackageStatusLocked(status, newOptimisticLockId, packageVersions);
return true;
}
- // Caller should be synchronized(this).
- private void writePackageStatusInternal(Integer status, int optimisticLockId,
+ @GuardedBy("this")
+ private void writePackageStatusLocked(Integer status, int optimisticLockId,
PackageVersions packageVersions) throws IOException {
if ((status == null) != (packageVersions == null)) {
throw new IllegalArgumentException(
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index cb8416b..45e9cc7 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -73,11 +73,13 @@
ret = (sHal == nullptr) ? NullptrStatus<R>()
: (*sHal.*fn)(std::forward<Args1>(args1)...);
- if (!ret.isOk()) {
- ALOGE("Failed to issue command to vibrator HAL. Retrying.");
- // Restoring connection to the HAL.
- sHal = I::tryGetService();
+ if (ret.isOk()) {
+ break;
}
+
+ ALOGE("Failed to issue command to vibrator HAL. Retrying.");
+ // Restoring connection to the HAL.
+ sHal = I::tryGetService();
}
return ret;
}
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 37ae782..2dfd8b9 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -59,7 +59,7 @@
static bool wakeup_init = false;
static sem_t wakeup_sem;
-extern sp<IPower> gPowerHal;
+extern sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0;
extern std::mutex gPowerHalMutex;
extern bool getPowerHal();
@@ -203,7 +203,7 @@
return -1;
}
- Return<void> ret = gPowerHal->getPlatformLowPowerStats(
+ Return<void> ret = gPowerHalV1_0->getPlatformLowPowerStats(
[&offset, &remaining, &total_added](hidl_vec<PowerStatePlatformSleepState> states,
Status status) {
if (status != Status::SUCCESS)
@@ -257,7 +257,7 @@
if (!ret.isOk()) {
ALOGE("getPlatformLowPowerStats() failed: power HAL service not available");
- gPowerHal = nullptr;
+ gPowerHalV1_0 = nullptr;
return -1;
}
}
@@ -288,7 +288,7 @@
}
//Trying to cast to 1.1, this will succeed only for devices supporting 1.1
- gPowerHal_1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHal);
+ gPowerHal_1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
if (gPowerHal_1_1 == nullptr) {
//This device does not support IPower@1.1, exiting gracefully
return 0;
@@ -351,7 +351,7 @@
if (!ret.isOk()) {
ALOGE("getSubsystemLowPowerStats() failed: power HAL service not available");
- gPowerHal = nullptr;
+ gPowerHalV1_0 = nullptr;
return -1;
}
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index edd7d53..4fb2ae3 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1523,6 +1523,10 @@
<< " satellites:: " << std::endl;
}
+ internalState << "constellation: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL; "
+ << "ephemerisType: 0=Eph, 1=Alm, 2=?; "
+ << "ephemerisSource: 0=Demod, 1=Supl, 2=Server, 3=?; "
+ << "ephemerisHealth: 0=Good, 1=Bad, 2=?" << std::endl;
for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
internalState << "svid: " << data.satelliteDataArray[i].svid
<< ", constellation: "
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 29924dd..2db7dbe 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -18,7 +18,7 @@
//#define LOG_NDEBUG 0
-#include <android/hardware/power/1.0/IPower.h>
+#include <android/hardware/power/1.1/IPower.h>
#include "JNIHelp.h"
#include "jni.h"
@@ -41,7 +41,7 @@
using android::hardware::Return;
using android::hardware::Void;
-using android::hardware::power::V1_0::IPower;
+using android::hardware::power::V1_1::IPower;
using android::hardware::power::V1_0::PowerHint;
using android::hardware::power::V1_0::Feature;
using android::String8;
@@ -57,13 +57,14 @@
// ----------------------------------------------------------------------------
static jobject gPowerManagerServiceObj;
-sp<IPower> gPowerHal = nullptr;
+sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
+sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
bool gPowerHalExists = true;
std::mutex gPowerHalMutex;
static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
// Throttling interval for user activity calls.
-static const nsecs_t MIN_TIME_BETWEEN_USERACTIVITIES = 500 * 1000000L; // 500ms
+static const nsecs_t MIN_TIME_BETWEEN_USERACTIVITIES = 100 * 1000000L; // 100ms
// ----------------------------------------------------------------------------
@@ -80,16 +81,17 @@
// Check validity of current handle to the power HAL service, and call getService() if necessary.
// The caller must be holding gPowerHalMutex.
bool getPowerHal() {
- if (gPowerHalExists && gPowerHal == nullptr) {
- gPowerHal = IPower::getService();
- if (gPowerHal != nullptr) {
+ if (gPowerHalExists && gPowerHalV1_0 == nullptr) {
+ gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
+ if (gPowerHalV1_0 != nullptr) {
+ gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
ALOGI("Loaded power HAL service");
} else {
ALOGI("Couldn't load power HAL service");
gPowerHalExists = false;
}
}
- return gPowerHal != nullptr;
+ return gPowerHalV1_0 != nullptr;
}
// Check if a call to a power HAL function failed; if so, log the failure and invalidate the
@@ -97,19 +99,11 @@
static void processReturn(const Return<void> &ret, const char* functionName) {
if (!ret.isOk()) {
ALOGE("%s() failed: power HAL service not available.", functionName);
- gPowerHal = nullptr;
+ gPowerHalV1_0 = nullptr;
}
}
void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
- // Tell the power HAL when user activity occurs.
- gPowerHalMutex.lock();
- if (getPowerHal()) {
- Return<void> ret = gPowerHal->powerHint(PowerHint::INTERACTION, 0);
- processReturn(ret, "powerHint");
- }
- gPowerHalMutex.unlock();
-
if (gPowerManagerServiceObj) {
// Throttle calls into user activity by event type.
// We're a little conservative about argument checking here in case the caller
@@ -124,6 +118,21 @@
return;
}
gLastEventTime[eventType] = eventTime;
+
+
+ // Tell the power HAL when user activity occurs.
+ gPowerHalMutex.lock();
+ if (getPowerHal()) {
+ Return<void> ret;
+ if (gPowerHalV1_1 != nullptr) {
+ ret = gPowerHalV1_1->powerHintAsync(PowerHint::INTERACTION, 0);
+ } else {
+ ret = gPowerHalV1_0->powerHint(PowerHint::INTERACTION, 0);
+ }
+ processReturn(ret, "powerHint");
+ }
+ gPowerHalMutex.unlock();
+
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -159,7 +168,7 @@
std::lock_guard<std::mutex> lock(gPowerHalMutex);
if (getPowerHal()) {
android::base::Timer t;
- Return<void> ret = gPowerHal->setInteractive(enable);
+ Return<void> ret = gPowerHalV1_0->setInteractive(enable);
processReturn(ret, "setInteractive");
if (t.duration() > 20ms) {
ALOGD("Excessive delay in setInteractive(%s) while turning screen %s",
@@ -187,7 +196,12 @@
static void nativeSendPowerHint(JNIEnv *env, jclass clazz, jint hintId, jint data) {
std::lock_guard<std::mutex> lock(gPowerHalMutex);
if (getPowerHal()) {
- Return<void> ret = gPowerHal->powerHint((PowerHint)hintId, data);
+ Return<void> ret;
+ if (gPowerHalV1_1 != nullptr) {
+ ret = gPowerHalV1_1->powerHintAsync((PowerHint)hintId, data);
+ } else {
+ ret = gPowerHalV1_0->powerHint((PowerHint)hintId, data);
+ }
processReturn(ret, "powerHint");
}
}
@@ -195,7 +209,7 @@
static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint data) {
std::lock_guard<std::mutex> lock(gPowerHalMutex);
if (getPowerHal()) {
- Return<void> ret = gPowerHal->setFeature((Feature)featureId, static_cast<bool>(data));
+ Return<void> ret = gPowerHalV1_0->setFeature((Feature)featureId, static_cast<bool>(data));
processReturn(ret, "setFeature");
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c2a5b6c..d10cc02 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -763,13 +763,6 @@
mContentResolver = context.getContentResolver();
- if (!disableCameraService) {
- Slog.i(TAG, "Camera Service Proxy");
- traceBeginAndSlog("StartCameraServiceProxy");
- mSystemServiceManager.startService(CameraServiceProxy.class);
- traceEnd();
- }
-
// The AccountManager must come before the ContentService
traceBeginAndSlog("StartAccountManagerService");
mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS);
@@ -1516,6 +1509,12 @@
}
}
+ if (!disableCameraService) {
+ traceBeginAndSlog("StartCameraServiceProxy");
+ mSystemServiceManager.startService(CameraServiceProxy.class);
+ traceEnd();
+ }
+
// Before things start rolling, be sure we have decided whether
// we are in safe mode.
final boolean safeMode = wm.detectSafeMode();
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 3ec8380..6c417a9 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -263,6 +263,8 @@
Preconditions.checkFlagsArgument(selectionFlags,
PrintManager.DISABLED_SERVICES | PrintManager.ENABLED_SERVICES);
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRINT_SERVICES, null);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -316,6 +318,8 @@
@Override
public List<RecommendationInfo> getPrintServiceRecommendations(int userId) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS, null);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -538,6 +542,8 @@
int userId) throws RemoteException {
listener = Preconditions.checkNotNull(listener);
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRINT_SERVICES,
+ null);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -560,6 +566,8 @@
int userId) {
listener = Preconditions.checkNotNull(listener);
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRINT_SERVICES,
+ null);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -583,6 +591,8 @@
throws RemoteException {
listener = Preconditions.checkNotNull(listener);
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS, null);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -605,6 +615,8 @@
IRecommendationsChangeListener listener, int userId) {
listener = Preconditions.checkNotNull(listener);
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS, null);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -888,12 +900,12 @@
private int resolveCallingAppEnforcingPermissions(int appId) {
final int callingUid = Binder.getCallingUid();
- if (callingUid == 0 || callingUid == Process.SYSTEM_UID
- || callingUid == Process.SHELL_UID) {
+ if (callingUid == 0) {
return appId;
}
final int callingAppId = UserHandle.getAppId(callingUid);
- if (appId == callingAppId) {
+ if (appId == callingAppId || callingAppId == Process.SHELL_UID
+ || callingAppId == Process.SYSTEM_UID) {
return appId;
}
if (mContext.checkCallingPermission(
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 807703b..f7d2a02 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -76,7 +76,8 @@
@Mock Vibrator mVibrator;
@Mock android.media.IRingtonePlayer mRingtonePlayer;
@Mock Light mLight;
- @Mock Handler mHandler;
+ @Mock
+ NotificationManagerService.WorkerHandler mHandler;
@Mock
NotificationUsageStats mUsageStats;
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
new file mode 100644
index 0000000..e527644
--- /dev/null
+++ b/services/tests/notification/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 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.notification;
+
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.service.notification.Adjustment;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+public class NotificationAdjustmentExtractorTest extends NotificationTestCase {
+
+ @Test
+ public void testExtractsAdjustment() {
+ NotificationAdjustmentExtractor extractor = new NotificationAdjustmentExtractor();
+
+ NotificationRecord r = generateRecord();
+
+ Bundle signals = new Bundle();
+ signals.putString(Adjustment.KEY_GROUP_KEY, GroupHelper.AUTOGROUP_KEY);
+ ArrayList<SnoozeCriterion> snoozeCriteria = new ArrayList<>();
+ snoozeCriteria.add(new SnoozeCriterion("n", "n", "n"));
+ signals.putParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA, snoozeCriteria);
+ ArrayList<String> people = new ArrayList<>();
+ people.add("you");
+ signals.putStringArrayList(Adjustment.KEY_PEOPLE, people);
+ Adjustment adjustment = new Adjustment("pkg", r.getKey(), signals, "", 0);
+ r.addAdjustment(adjustment);
+
+ assertFalse(r.getGroupKey().contains(GroupHelper.AUTOGROUP_KEY));
+ assertFalse(Objects.equals(people, r.getPeopleOverride()));
+ assertFalse(Objects.equals(snoozeCriteria, r.getSnoozeCriteria()));
+
+ assertNull(extractor.process(r));
+
+ assertTrue(r.getGroupKey().contains(GroupHelper.AUTOGROUP_KEY));
+ assertEquals(people, r.getPeopleOverride());
+ assertEquals(snoozeCriteria, r.getSnoozeCriteria());
+ }
+
+ @Test
+ public void testExtractsAdjustments() {
+ NotificationAdjustmentExtractor extractor = new NotificationAdjustmentExtractor();
+
+ NotificationRecord r = generateRecord();
+
+ Bundle pSignals = new Bundle();
+ ArrayList<String> people = new ArrayList<>();
+ people.add("you");
+ pSignals.putStringArrayList(Adjustment.KEY_PEOPLE, people);
+ Adjustment pAdjustment = new Adjustment("pkg", r.getKey(), pSignals, "", 0);
+ r.addAdjustment(pAdjustment);
+
+ Bundle sSignals = new Bundle();
+ ArrayList<SnoozeCriterion> snoozeCriteria = new ArrayList<>();
+ snoozeCriteria.add(new SnoozeCriterion("n", "n", "n"));
+ sSignals.putParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA, snoozeCriteria);
+ Adjustment sAdjustment = new Adjustment("pkg", r.getKey(), sSignals, "", 0);
+ r.addAdjustment(sAdjustment);
+
+ Bundle gSignals = new Bundle();
+ gSignals.putString(Adjustment.KEY_GROUP_KEY, GroupHelper.AUTOGROUP_KEY);
+ Adjustment gAdjustment = new Adjustment("pkg", r.getKey(), gSignals, "", 0);
+ r.addAdjustment(gAdjustment);
+
+ assertFalse(r.getGroupKey().contains(GroupHelper.AUTOGROUP_KEY));
+ assertFalse(Objects.equals(people, r.getPeopleOverride()));
+ assertFalse(Objects.equals(snoozeCriteria, r.getSnoozeCriteria()));
+
+ assertNull(extractor.process(r));
+
+ assertTrue(r.getGroupKey().contains(GroupHelper.AUTOGROUP_KEY));
+ assertEquals(people, r.getPeopleOverride());
+ assertEquals(snoozeCriteria, r.getSnoozeCriteria());
+ }
+
+ private NotificationRecord generateRecord() {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
+ final Notification.Builder builder = new Notification.Builder(getContext())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+ Notification n = builder.build();
+ StatusBarNotification sbn = new StatusBarNotification("", "", 0, "", 0,
+ 0, n, UserHandle.ALL, null, System.currentTimeMillis());
+ return new NotificationRecord(getContext(), sbn, channel);
+ }
+}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationChannelExtractorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationChannelExtractorTest.java
new file mode 100644
index 0000000..d75213c
--- /dev/null
+++ b/services/tests/notification/src/com/android/server/notification/NotificationChannelExtractorTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 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.notification;
+
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class NotificationChannelExtractorTest extends NotificationTestCase {
+
+ @Mock RankingConfig mConfig;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testExtractsUpdatedChannel() {
+ NotificationChannelExtractor extractor = new NotificationChannelExtractor();
+ extractor.setConfig(mConfig);
+
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
+ final Notification.Builder builder = new Notification.Builder(getContext())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+ Notification n = builder.build();
+ StatusBarNotification sbn = new StatusBarNotification("", "", 0, "", 0,
+ 0, n, UserHandle.ALL, null, System.currentTimeMillis());
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+
+ NotificationChannel updatedChannel =
+ new NotificationChannel("a", "", IMPORTANCE_HIGH);
+ when(mConfig.getNotificationChannel(any(), anyInt(), eq("a"), eq(false)))
+ .thenReturn(updatedChannel);
+
+ assertNull(extractor.process(r));
+ assertEquals(updatedChannel, r.getChannel());
+ }
+
+}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java b/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java
index 3007cb1..f457f6a 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java
@@ -25,8 +25,14 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.internal.util.FastXmlSerializer;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -50,4 +56,15 @@
channel.setBlockableSystem(true);
assertEquals(true, channel.isBlockableSystem());
}
+
+ @Test
+ public void testEmptyVibration_noException() throws Exception {
+ NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
+ channel.setVibrationPattern(new long[0]);
+
+ XmlSerializer serializer = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ channel.writeXml(serializer);
+ }
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
new file mode 100644
index 0000000..d2f608e
--- /dev/null
+++ b/services/tests/notification/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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.notification;
+
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+
+import org.junit.Test;
+
+public class NotificationIntrusivenessExtractorTest extends NotificationTestCase {
+
+ @Test
+ public void testNonIntrusive() {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
+ final Notification.Builder builder = new Notification.Builder(getContext())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+ Notification n = builder.build();
+ StatusBarNotification sbn = new StatusBarNotification("", "", 0, "", 0,
+ 0, n, UserHandle.ALL, null, System.currentTimeMillis());
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+
+ assertNull(new NotificationIntrusivenessExtractor().process(r));
+ }
+
+ @Test
+ public void testIntrusive_fillScreen() {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+ final Notification.Builder builder = new Notification.Builder(getContext())
+ .setContentTitle("foo")
+ .setFullScreenIntent(PendingIntent.getActivity(
+ getContext(), 0, new Intent(""), 0), true)
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+ Notification n = builder.build();
+ StatusBarNotification sbn = new StatusBarNotification("", "", 0, "", 0,
+ 0, n, UserHandle.ALL, null, System.currentTimeMillis());
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+
+ assertNotNull(new NotificationIntrusivenessExtractor().process(r));
+ }
+}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 1a5814b..ae2253e 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -20,6 +20,9 @@
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static com.android.server.notification.NotificationManagerService
+ .MESSAGE_SEND_RANKING_UPDATE;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -31,9 +34,12 @@
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -54,6 +60,9 @@
import android.graphics.Color;
import android.media.AudioManager;
import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings.Secure;
@@ -63,7 +72,22 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import android.util.ArrayMap;
import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
import java.io.File;
import java.io.FileInputStream;
@@ -71,16 +95,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import com.android.server.lights.Light;
-import com.android.server.lights.LightsManager;
+import java.util.Map;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -109,6 +124,7 @@
private AudioManager mAudioManager;
@Mock
ActivityManager mActivityManager;
+ NotificationManagerService.WorkerHandler mHandler;
private NotificationChannel mTestNotificationChannel = new NotificationChannel(
TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
@@ -152,6 +168,9 @@
mNotificationManagerService = new TestableNotificationManagerService(mContext);
+ // Use this testable looper.
+ mTestableLooper = TestableLooper.get(this);
+ mHandler = mNotificationManagerService.new WorkerHandler(mTestableLooper.getLooper());
// MockPackageManager - default returns ApplicationInfo with matching calling UID
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.uid = uid;
@@ -162,8 +181,6 @@
final LightsManager mockLightsManager = mock(LightsManager.class);
when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
- // Use this testable looper.
- mTestableLooper = TestableLooper.get(this);
mFile = new File(mContext.getCacheDir(), "test.xml");
mFile.createNewFile();
@@ -174,10 +191,11 @@
null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
try {
- mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager,
- mPackageManagerClient, mockLightsManager, mNotificationListeners,
- mNotificationAssistants, mConditionProviders, mCompanionMgr,
- mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper);
+ mNotificationManagerService.init(mTestableLooper.getLooper(),
+ mPackageManager, mPackageManagerClient, mockLightsManager,
+ mNotificationListeners, mNotificationAssistants, mConditionProviders,
+ mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
+ mGroupHelper);
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
@@ -234,6 +252,43 @@
return new NotificationRecord(mContext, sbn, channel);
}
+ private Map<String, Answer> getSignalExtractorSideEffects() {
+ Map<String, Answer> answers = new ArrayMap<>();
+
+ answers.put("override group key", invocationOnMock -> {
+ ((NotificationRecord) invocationOnMock.getArguments()[0])
+ .setOverrideGroupKey("bananas");
+ return null;
+ });
+ answers.put("override people", invocationOnMock -> {
+ ((NotificationRecord) invocationOnMock.getArguments()[0])
+ .setPeopleOverride(new ArrayList<>());
+ return null;
+ });
+ answers.put("snooze criteria", invocationOnMock -> {
+ ((NotificationRecord) invocationOnMock.getArguments()[0])
+ .setSnoozeCriteria(new ArrayList<>());
+ return null;
+ });
+ answers.put("notification channel", invocationOnMock -> {
+ ((NotificationRecord) invocationOnMock.getArguments()[0])
+ .updateNotificationChannel(new NotificationChannel("a", "", IMPORTANCE_LOW));
+ return null;
+ });
+ answers.put("badging", invocationOnMock -> {
+ NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0];
+ r.setShowBadge(!r.canShowBadge());
+ return null;
+ });
+ answers.put("package visibility", invocationOnMock -> {
+ ((NotificationRecord) invocationOnMock.getArguments()[0]).setPackageVisibilityOverride(
+ Notification.VISIBILITY_SECRET);
+ return null;
+ });
+
+ return answers;
+ }
+
@Test
public void testCreateNotificationChannels_SingleChannel() throws Exception {
final NotificationChannel channel =
@@ -1317,11 +1372,59 @@
mNotificationManagerService.addNotification(otherPackage);
// Same notifications are enqueued as posted, everything counts b/c id and tag don't match
- assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, new UserHandle(uid).getIdentifier(), 0, null));
- assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, new UserHandle(uid).getIdentifier(), 0, "tag2"));
- assertEquals(2, mNotificationManagerService.getNotificationCountLocked("a", new UserHandle(uid).getIdentifier(), 0, "banana"));
+ int userId = new UserHandle(uid).getIdentifier();
+ assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, null));
+ assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag2"));
+ assertEquals(2, mNotificationManagerService.getNotificationCountLocked("a", userId, 0, "banana"));
// exclude a known notification - it's excluded from only the posted list, not enqueued
- assertEquals(39, mNotificationManagerService.getNotificationCountLocked(PKG, new UserHandle(uid).getIdentifier(), 0, "tag"));
+ assertEquals(39, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag"));
+ }
+
+ @Test
+ public void testModifyAutogroup_requestsSort() throws Exception {
+ RankingHandler rh = mock(RankingHandler.class);
+ mNotificationManagerService.setRankingHandler(rh);
+
+ final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ mNotificationManagerService.addNotification(r);
+ mNotificationManagerService.addAutogroupKeyLocked(r.getKey());
+ mNotificationManagerService.removeAutogroupKeyLocked(r.getKey());
+
+ verify(rh, times(2)).requestSort();
+ }
+
+ @Test
+ public void testHandleRankingSort_sendsUpdateOnSignalExtractorChange() throws Exception {
+ mNotificationManagerService.setRankingHelper(mRankingHelper);
+ NotificationManagerService.WorkerHandler handler = mock(
+ NotificationManagerService.WorkerHandler.class);
+ mNotificationManagerService.setHandler(handler);
+
+ Map<String, Answer> answers = getSignalExtractorSideEffects();
+ for (String message : answers.keySet()) {
+ mNotificationManagerService.clearNotifications();
+ final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ mNotificationManagerService.addNotification(r);
+
+ doAnswer(answers.get(message)).when(mRankingHelper).extractSignals(r);
+
+ mNotificationManagerService.handleRankingSort();
+ }
+ verify(handler, times(answers.size())).scheduleSendRankingUpdate();
+ }
+
+ @Test
+ public void testHandleRankingSort_noUpdateWhenNoSignalChange() throws Exception {
+ mNotificationManagerService.setRankingHelper(mRankingHelper);
+ NotificationManagerService.WorkerHandler handler = mock(
+ NotificationManagerService.WorkerHandler.class);
+ mNotificationManagerService.setHandler(handler);
+
+ final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ mNotificationManagerService.addNotification(r);
+
+ mNotificationManagerService.handleRankingSort();
+ verify(handler, never()).scheduleSendRankingUpdate();
}
}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 5a72e6b..801479b 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -78,6 +78,9 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SmallTest
@@ -630,6 +633,8 @@
// all fields should be changed
assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel.getId(), false));
+
+ verify(mHandler, times(1)).requestSort();
}
@Test
@@ -712,6 +717,8 @@
assertFalse(savedChannel.canBypassDnd());
assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
+
+ verify(mHandler, never()).requestSort();
}
@Test
@@ -1058,6 +1065,8 @@
// notDeleted
assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID).size());
+
+ verify(mHandler, never()).requestSort();
}
@Test
@@ -1159,6 +1168,7 @@
NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
assertEquals(ncg, mHelper.getNotificationChannelGroups(PKG, UID).iterator().next());
+ verify(mHandler, never()).requestSort();
}
@Test
@@ -1275,6 +1285,8 @@
actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
assertEquals("goodbye", actual.getName());
assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
+
+ verify(mHandler, times(1)).requestSort();
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index ad8303a..11e383c 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -24,15 +24,13 @@
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
-import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
-import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
-import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
+import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.telephony.CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG;
import static android.telephony.CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT;
@@ -41,10 +39,10 @@
import static android.text.format.Time.TIMEZONE_UTC;
import static com.android.server.net.NetworkPolicyManagerService.MAX_PROC_STATE_SEQ_HISTORY;
-import static com.android.server.net.NetworkPolicyManagerService.ProcStateSeqHistory;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -53,22 +51,19 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Matchers.isNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -97,6 +92,7 @@
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
@@ -112,18 +108,21 @@
import android.support.test.runner.AndroidJUnit4;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.format.Time;
import android.util.Log;
+import android.util.Pair;
import android.util.TrustedTime;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.net.NetworkPolicyManagerService;
+import com.android.server.net.NetworkPolicyManagerService.ProcStateSeqHistory;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -132,7 +131,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
@@ -156,8 +154,11 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.time.Instant;
+import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Calendar;
+import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -393,6 +394,11 @@
LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
}
+ @After
+ public void resetClock() throws Exception {
+ SubscriptionPlan.sNowOverride = -1;
+ }
+
@Test
public void testTurnRestrictBackgroundOn() throws Exception {
assertRestrictBackgroundOff(); // Sanity check.
@@ -778,6 +784,25 @@
assertTrue(mService.isUidForeground(UID_B));
}
+ private static long computeLastCycleBoundary(long currentTime, NetworkPolicy policy) {
+ SubscriptionPlan.sNowOverride = currentTime;
+ final Iterator<Pair<ZonedDateTime, ZonedDateTime>> it = NetworkPolicyManager
+ .cycleIterator(policy);
+ while (it.hasNext()) {
+ final Pair<ZonedDateTime, ZonedDateTime> cycle = it.next();
+ if (cycle.first.toInstant().toEpochMilli() < currentTime) {
+ return cycle.first.toInstant().toEpochMilli();
+ }
+ }
+ throw new IllegalStateException(
+ "Failed to find current cycle for " + policy + " at " + currentTime);
+ }
+
+ private static long computeNextCycleBoundary(long currentTime, NetworkPolicy policy) {
+ SubscriptionPlan.sNowOverride = currentTime;
+ return NetworkPolicyManager.cycleIterator(policy).next().second.toInstant().toEpochMilli();
+ }
+
@Test
public void testLastCycleBoundaryThisMonth() throws Exception {
// assume cycle day of "5th", which should be in same month
@@ -818,7 +843,7 @@
public void testLastCycleBoundaryLastMonthFebruary() throws Exception {
// assume cycle day of "30th" in february, which should clamp
final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
- final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
+ final long expectedCycle = parseTime("2007-02-28T23:59:59.999Z");
final NetworkPolicy policy = new NetworkPolicy(
sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false);
@@ -842,9 +867,9 @@
assertTimeEquals(parseTime("2007-01-29T00:00:00.000Z"),
computeNextCycleBoundary(parseTime("2007-01-14T00:00:00.000Z"), policy));
- assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"),
+ assertTimeEquals(parseTime("2007-02-28T23:59:59.999Z"),
computeNextCycleBoundary(parseTime("2007-02-14T00:00:00.000Z"), policy));
- assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"),
+ assertTimeEquals(parseTime("2007-02-28T23:59:59.999Z"),
computeLastCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy));
assertTimeEquals(parseTime("2007-03-29T00:00:00.000Z"),
computeNextCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy));
@@ -922,7 +947,7 @@
@Test
public void testLastCycleBoundaryDST() throws Exception {
- final long currentTime = parseTime("1989-01-02T07:30:00.000");
+ final long currentTime = parseTime("1989-01-02T07:30:00.000Z");
final long expectedCycle = parseTime("1988-12-03T02:00:00.000Z");
final NetworkPolicy policy = new NetworkPolicy(
@@ -932,26 +957,16 @@
}
@Test
- public void testLastCycleBoundaryJanuaryDST() throws Exception {
- final long currentTime = parseTime("1989-01-26T21:00:00.000Z");
- final long expectedCycle = parseTime("1989-01-01T01:59:59.000Z");
-
- final NetworkPolicy policy = new NetworkPolicy(
- sTemplateWifi, 32, "America/Argentina/Buenos_Aires", 1024L, 1024L, false);
- final long actualCycle = computeLastCycleBoundary(currentTime, policy);
- assertTimeEquals(expectedCycle, actualCycle);
- }
-
- @Test
public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
NetworkState[] state = null;
NetworkStats stats = null;
- final long TIME_FEB_15 = 1171497600000L;
- final long TIME_MAR_10 = 1173484800000L;
final int CYCLE_DAY = 15;
+ final long NOW = parseTime("2007-03-10T00:00Z");
+ final long CYCLE_START = parseTime("2007-02-15T00:00Z");
+ final long CYCLE_END = parseTime("2007-03-15T00:00Z");
- setCurrentTimeMillis(TIME_MAR_10);
+ setCurrentTimeMillis(NOW);
// first, pretend that wifi network comes online. no policy active,
// which means we shouldn't push limit to interface.
@@ -971,7 +986,7 @@
// pretend that 512 bytes total have happened
stats = new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L);
- when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
+ when(mStatsService.getNetworkTotalBytes(sTemplateWifi, CYCLE_START, CYCLE_END))
.thenReturn(stats.getTotalBytes());
mPolicyListener.expect().onMeteredIfacesChanged(any());
@@ -991,11 +1006,12 @@
NetworkStats stats = null;
Future<String> tagFuture = null;
- final long TIME_FEB_15 = 1171497600000L;
- final long TIME_MAR_10 = 1173484800000L;
final int CYCLE_DAY = 15;
+ final long NOW = parseTime("2007-03-10T00:00Z");
+ final long CYCLE_START = parseTime("2007-02-15T00:00Z");
+ final long CYCLE_END = parseTime("2007-03-15T00:00Z");
- setCurrentTimeMillis(TIME_MAR_10);
+ setCurrentTimeMillis(NOW);
// assign wifi policy
state = new NetworkState[] {};
@@ -1005,8 +1021,8 @@
{
expectCurrentTime();
when(mConnManager.getAllNetworkState()).thenReturn(state);
- when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
- currentTimeMillis())).thenReturn(stats.getTotalBytes());
+ when(mStatsService.getNetworkTotalBytes(sTemplateWifi, CYCLE_START,
+ CYCLE_END)).thenReturn(stats.getTotalBytes());
mPolicyListener.expect().onMeteredIfacesChanged(any());
setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1
@@ -1024,8 +1040,8 @@
{
expectCurrentTime();
when(mConnManager.getAllNetworkState()).thenReturn(state);
- when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
- currentTimeMillis())).thenReturn(stats.getTotalBytes());
+ when(mStatsService.getNetworkTotalBytes(sTemplateWifi, CYCLE_START,
+ CYCLE_END)).thenReturn(stats.getTotalBytes());
mPolicyListener.expect().onMeteredIfacesChanged(any());
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
@@ -1043,8 +1059,8 @@
{
expectCurrentTime();
- when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
- currentTimeMillis())).thenReturn(stats.getTotalBytes());
+ when(mStatsService.getNetworkTotalBytes(sTemplateWifi, CYCLE_START,
+ CYCLE_END)).thenReturn(stats.getTotalBytes());
tagFuture = expectEnqueueNotification();
mNetworkObserver.limitReached(null, TEST_IFACE);
@@ -1061,8 +1077,8 @@
{
expectCurrentTime();
- when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
- currentTimeMillis())).thenReturn(stats.getTotalBytes());
+ when(mStatsService.getNetworkTotalBytes(sTemplateWifi, CYCLE_START,
+ CYCLE_END)).thenReturn(stats.getTotalBytes());
tagFuture = expectEnqueueNotification();
mNetworkObserver.limitReached(null, TEST_IFACE);
@@ -1077,8 +1093,8 @@
{
expectCurrentTime();
when(mConnManager.getAllNetworkState()).thenReturn(state);
- when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
- currentTimeMillis())).thenReturn(stats.getTotalBytes());
+ when(mStatsService.getNetworkTotalBytes(sTemplateWifi, CYCLE_START,
+ CYCLE_END)).thenReturn(stats.getTotalBytes());
tagFuture = expectEnqueueNotification();
mPolicyListener.expect().onMeteredIfacesChanged(any());
@@ -1129,6 +1145,15 @@
}
@Test
+ public void testConversion() throws Exception {
+ NetworkTemplate template = NetworkTemplate.buildTemplateMobileWildcard();
+ NetworkPolicy before = new NetworkPolicy(template, 12, "Israel", 123, 456, true);
+ NetworkPolicy after = SubscriptionPlan.convert(SubscriptionPlan.convert(before));
+ after.template = before.template;
+ assertEquals(before, after);
+ }
+
+ @Test
public void testOnUidStateChanged_notifyAMS() throws Exception {
final long procStateSeq = 222;
callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq);
@@ -1470,9 +1495,7 @@
}
private static long parseTime(String time) {
- final Time result = new Time();
- result.parse3339(time);
- return result.toMillis(true);
+ return ZonedDateTime.parse(time).toInstant().toEpochMilli();
}
private void setNetworkPolicies(NetworkPolicy... policies) {
@@ -1559,16 +1582,15 @@
}
private static String formatTime(long millis) {
- final Time time = new Time(Time.TIMEZONE_UTC);
- time.set(millis);
- return time.format3339(false);
+ return Instant.ofEpochMilli(millis) + " [" + millis + "]";
}
private static void assertEqualsFuzzy(long expected, long actual, long fuzzy) {
final long low = expected - fuzzy;
final long high = expected + fuzzy;
if (actual < low || actual > high) {
- fail("value " + actual + " is outside [" + low + "," + high + "]");
+ fail("value " + formatTime(actual) + " is outside [" + formatTime(low) + ","
+ + formatTime(high) + "]");
}
}
@@ -1643,6 +1665,7 @@
}
private void setCurrentTimeMillis(long currentTimeMillis) {
+ SubscriptionPlan.sNowOverride = currentTimeMillis;
mStartTime = currentTimeMillis;
mElapsedRealtime = 0L;
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/BackupPasswordManagerTest.java b/services/tests/servicestests/src/com/android/server/backup/BackupPasswordManagerTest.java
new file mode 100644
index 0000000..04c0251
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/BackupPasswordManagerTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2017 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.backup;
+
+import static com.android.server.testutis.TestUtils.assertExpectException;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doThrow;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.backup.utils.PasswordUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.security.SecureRandom;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BackupPasswordManagerTest {
+ private static final String PASSWORD_VERSION_FILE_NAME = "pwversion";
+ private static final String PASSWORD_HASH_FILE_NAME = "pwhash";
+ private static final String V1_HASH_ALGORITHM = "PBKDF2WithHmacSHA1And8bit";
+
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+ @Mock private Context mContext;
+
+ private File mStateFolder;
+ private BackupPasswordManager mPasswordManager;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mStateFolder = mTemporaryFolder.newFolder();
+ mPasswordManager = new BackupPasswordManager(mContext, mStateFolder, new SecureRandom());
+ }
+
+ @Test
+ public void hasBackupPassword_isFalseIfFileDoesNotExist() {
+ assertThat(mPasswordManager.hasBackupPassword()).isFalse();
+ }
+
+ @Test
+ public void hasBackupPassword_isTrueIfFileExists() throws Exception {
+ mPasswordManager.setBackupPassword(null, "password1234");
+ assertThat(mPasswordManager.hasBackupPassword()).isTrue();
+ }
+
+ @Test
+ public void hasBackupPassword_throwsSecurityExceptionIfLacksPermission() {
+ setDoesNotHavePermission();
+
+ assertExpectException(
+ SecurityException.class,
+ /* expectedExceptionMessageRegex */ null,
+ () -> mPasswordManager.hasBackupPassword());
+ }
+
+ @Test
+ public void backupPasswordMatches_isTrueIfNoPassword() {
+ assertThat(mPasswordManager.backupPasswordMatches("anything")).isTrue();
+ }
+
+ @Test
+ public void backupPasswordMatches_isTrueForSamePassword() {
+ String password = "password1234";
+ mPasswordManager.setBackupPassword(null, password);
+ assertThat(mPasswordManager.backupPasswordMatches(password)).isTrue();
+ }
+
+ @Test
+ public void backupPasswordMatches_isFalseForDifferentPassword() {
+ mPasswordManager.setBackupPassword(null, "shiba");
+ assertThat(mPasswordManager.backupPasswordMatches("corgi")).isFalse();
+ }
+
+ @Test
+ public void backupPasswordMatches_worksForV1HashIfVersionIsV1() throws Exception {
+ String password = "corgi\uFFFF";
+ writePasswordVersionToFile(1);
+ writeV1HashToFile(password, saltFixture());
+
+ // Reconstruct so it reloads from filesystem
+ mPasswordManager = new BackupPasswordManager(mContext, mStateFolder, new SecureRandom());
+
+ assertThat(mPasswordManager.backupPasswordMatches(password)).isTrue();
+ }
+
+ @Test
+ public void backupPasswordMatches_failsForV1HashIfVersionIsV2() throws Exception {
+ // The algorithms produce identical hashes except if the password contains higher-order
+ // unicode. See
+ // https://android-developers.googleblog.com/2013/12/changes-to-secretkeyfactory-api-in.html
+ String password = "corgi\uFFFF";
+ writePasswordVersionToFile(2);
+ writeV1HashToFile(password, saltFixture());
+
+ // Reconstruct so it reloads from filesystem
+ mPasswordManager = new BackupPasswordManager(mContext, mStateFolder, new SecureRandom());
+
+ assertThat(mPasswordManager.backupPasswordMatches(password)).isFalse();
+ }
+
+ @Test
+ public void backupPasswordMatches_throwsSecurityExceptionIfLacksPermission() {
+ setDoesNotHavePermission();
+
+ assertExpectException(
+ SecurityException.class,
+ /* expectedExceptionMessageRegex */ null,
+ () -> mPasswordManager.backupPasswordMatches("password123"));
+ }
+
+ @Test
+ public void setBackupPassword_persistsPasswordToFile() {
+ String password = "shiba";
+
+ mPasswordManager.setBackupPassword(null, password);
+
+ BackupPasswordManager newManager = new BackupPasswordManager(
+ mContext, mStateFolder, new SecureRandom());
+ assertThat(newManager.backupPasswordMatches(password)).isTrue();
+ }
+
+ @Test
+ public void setBackupPassword_failsIfCurrentPasswordIsWrong() {
+ String secondPassword = "second password";
+ mPasswordManager.setBackupPassword(null, "first password");
+
+ boolean result = mPasswordManager.setBackupPassword(
+ "incorrect pass", secondPassword);
+
+ BackupPasswordManager newManager = new BackupPasswordManager(
+ mContext, mStateFolder, new SecureRandom());
+ assertThat(result).isFalse();
+ assertThat(newManager.backupPasswordMatches(secondPassword)).isFalse();
+ }
+
+ @Test
+ public void setBackupPassword_throwsSecurityExceptionIfLacksPermission() {
+ setDoesNotHavePermission();
+
+ assertExpectException(
+ SecurityException.class,
+ /* expectedExceptionMessageRegex */ null,
+ () -> mPasswordManager.setBackupPassword(
+ "password123", "password111"));
+ }
+
+ private byte[] saltFixture() {
+ byte[] bytes = new byte[64];
+ for (int i = 0; i < 64; i++) {
+ bytes[i] = (byte) i;
+ }
+ return bytes;
+ }
+
+ private void setDoesNotHavePermission() {
+ doThrow(new SecurityException()).when(mContext)
+ .enforceCallingOrSelfPermission(anyString(), anyString());
+ }
+
+ private void writeV1HashToFile(String password, byte[] salt) throws Exception {
+ String hash = PasswordUtils.buildPasswordHash(
+ V1_HASH_ALGORITHM, password, salt, PasswordUtils.PBKDF2_HASH_ROUNDS);
+ writeHashAndSaltToFile(hash, salt);
+ }
+
+ private void writeHashAndSaltToFile(String hash, byte[] salt) throws Exception {
+ FileOutputStream fos = null;
+ DataOutputStream dos = null;
+
+ try {
+ File passwordHash = new File(mStateFolder, PASSWORD_HASH_FILE_NAME);
+ fos = new FileOutputStream(passwordHash);
+ dos = new DataOutputStream(fos);
+ dos.writeInt(salt.length);
+ dos.write(salt);
+ dos.writeUTF(hash);
+ dos.flush();
+ } finally {
+ if (dos != null) dos.close();
+ if (fos != null) fos.close();
+ }
+ }
+
+ private void writePasswordVersionToFile(int version) throws Exception {
+ FileOutputStream fos = null;
+ DataOutputStream dos = null;
+
+ try {
+ File passwordVersion = new File(mStateFolder, PASSWORD_VERSION_FILE_NAME);
+ fos = new FileOutputStream(passwordVersion);
+ dos = new DataOutputStream(fos);
+ dos.writeInt(version);
+ dos.flush();
+ } finally {
+ if (dos != null) dos.close();
+ if (fos != null) fos.close();
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java b/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
new file mode 100644
index 0000000..c27fd07
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 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.backup;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class DataChangedJournalTest {
+ private static final String GMAIL = "com.google.gmail";
+ private static final String DOCS = "com.google.docs";
+ private static final String GOOGLE_PLUS = "com.google.plus";
+
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+ @Mock private DataChangedJournal.Consumer mConsumer;
+
+ private File mFile;
+ private DataChangedJournal mJournal;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mFile = mTemporaryFolder.newFile();
+ mJournal = new DataChangedJournal(mFile);
+ }
+
+ @Test
+ public void addPackage_addsPackagesToEndOfFile() throws Exception {
+ mJournal.addPackage(GMAIL);
+ mJournal.addPackage(DOCS);
+ mJournal.addPackage(GOOGLE_PLUS);
+
+ FileInputStream fos = new FileInputStream(mFile);
+ DataInputStream dos = new DataInputStream(fos);
+ assertThat(dos.readUTF()).isEqualTo(GMAIL);
+ assertThat(dos.readUTF()).isEqualTo(DOCS);
+ assertThat(dos.readUTF()).isEqualTo(GOOGLE_PLUS);
+ assertThat(dos.available()).isEqualTo(0);
+ }
+
+ @Test
+ public void delete_deletesTheFile() throws Exception {
+ mJournal.addPackage(GMAIL);
+
+ mJournal.delete();
+
+ assertThat(mFile.exists()).isFalse();
+ }
+
+ @Test
+ public void equals_isTrueForTheSameFile() throws Exception {
+ assertThat(mJournal.equals(new DataChangedJournal(mFile))).isTrue();
+ }
+
+ @Test
+ public void equals_isFalseForDifferentFiles() throws Exception {
+ assertThat(mJournal.equals(new DataChangedJournal(mTemporaryFolder.newFile()))).isFalse();
+ }
+
+ @Test
+ public void forEach_iteratesThroughPackagesInFileInOrder() throws Exception {
+ mJournal.addPackage(GMAIL);
+ mJournal.addPackage(DOCS);
+
+ mJournal.forEach(mConsumer);
+
+ InOrder inOrder = Mockito.inOrder(mConsumer);
+ inOrder.verify(mConsumer).accept(GMAIL);
+ inOrder.verify(mConsumer).accept(DOCS);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void listJournals_returnsJournalsForEveryFileInDirectory() throws Exception {
+ File folder = mTemporaryFolder.newFolder();
+ DataChangedJournal.newJournal(folder);
+ DataChangedJournal.newJournal(folder);
+
+ ArrayList<DataChangedJournal> journals = DataChangedJournal.listJournals(folder);
+
+ assertThat(journals).hasSize(2);
+ }
+
+ @Test
+ public void newJournal_createsANewTemporaryFile() throws Exception {
+ File folder = mTemporaryFolder.newFolder();
+
+ DataChangedJournal.newJournal(folder);
+
+ assertThat(folder.listFiles()).hasLength(1);
+ }
+
+ @Test
+ public void toString_isSameAsFileToString() throws Exception {
+ assertThat(mJournal.toString()).isEqualTo(mFile.toString());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/DataStreamFileCodecTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/DataStreamFileCodecTest.java
new file mode 100644
index 0000000..bfb95c1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/DataStreamFileCodecTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 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.backup.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public final class DataStreamFileCodecTest {
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+ @Test
+ public void serialize_writesToTheFile() throws Exception {
+ File unicornFile = mTemporaryFolder.newFile();
+
+ DataStreamFileCodec<MythicalCreature> mythicalCreatureCodec = new DataStreamFileCodec<>(
+ unicornFile, new MythicalCreatureDataStreamCodec());
+ MythicalCreature unicorn = new MythicalCreature(
+ 10000, "Unicorn");
+ mythicalCreatureCodec.serialize(unicorn);
+
+ DataStreamFileCodec<MythicalCreature> newCodecWithSameFile = new DataStreamFileCodec<>(
+ unicornFile, new MythicalCreatureDataStreamCodec());
+ MythicalCreature deserializedUnicorn = newCodecWithSameFile.deserialize();
+
+ assertThat(deserializedUnicorn.averageLifespanInYears)
+ .isEqualTo(unicorn.averageLifespanInYears);
+ assertThat(deserializedUnicorn.name).isEqualTo(unicorn.name);
+ }
+
+ private static class MythicalCreature {
+ int averageLifespanInYears;
+ String name;
+
+ MythicalCreature(int averageLifespanInYears, String name) {
+ this.averageLifespanInYears = averageLifespanInYears;
+ this.name = name;
+ }
+ }
+
+ private static class MythicalCreatureDataStreamCodec implements
+ DataStreamCodec<MythicalCreature> {
+ @Override
+ public void serialize(MythicalCreature mythicalCreature,
+ DataOutputStream dataOutputStream) throws IOException {
+ dataOutputStream.writeInt(mythicalCreature.averageLifespanInYears);
+ dataOutputStream.writeUTF(mythicalCreature.name);
+ }
+
+ @Override
+ public MythicalCreature deserialize(DataInputStream dataInputStream)
+ throws IOException {
+ int years = dataInputStream.readInt();
+ String name = dataInputStream.readUTF();
+ return new MythicalCreature(years, name);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/SparseArrayUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/SparseArrayUtilsTest.java
new file mode 100644
index 0000000..db55120
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/SparseArrayUtilsTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 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.backup.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.SparseArray;
+
+import com.google.android.collect.Sets;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class SparseArrayUtilsTest {
+ @Test
+ public void union_mergesSets() {
+ SparseArray<HashSet<String>> sparseArray = new SparseArray<>();
+ sparseArray.append(12, Sets.newHashSet("a", "b", "c"));
+ sparseArray.append(45, Sets.newHashSet("d", "e"));
+ sparseArray.append(46, Sets.newHashSet());
+ sparseArray.append(66, Sets.newHashSet("a", "e", "f"));
+
+ assertThat(SparseArrayUtils.union(sparseArray)).isEqualTo(
+ Sets.newHashSet("a", "b", "c", "d", "e", "f"));
+ }
+
+ @Test
+ public void union_returnsEmptySetForEmptyList() {
+ SparseArray<HashSet<String>> sparseArray = new SparseArray<>();
+
+ assertThat(SparseArrayUtils.union(sparseArray)).isEqualTo(Sets.newHashSet());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index 4c77f62..b0325cb 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -347,11 +347,11 @@
}
public void testPersistentData_serializeUnserialize() {
- byte[] serialized = PersistentData.toBytes(PersistentData.TYPE_GATEKEEPER, SOME_USER_ID,
+ byte[] serialized = PersistentData.toBytes(PersistentData.TYPE_SP, SOME_USER_ID,
DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, PAYLOAD);
PersistentData deserialized = PersistentData.fromBytes(serialized);
- assertEquals(PersistentData.TYPE_GATEKEEPER, deserialized.type);
+ assertEquals(PersistentData.TYPE_SP, deserialized.type);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, deserialized.qualityForUi);
assertArrayEquals(PAYLOAD, deserialized.payload);
}
@@ -371,7 +371,7 @@
// the wire format in the future.
byte[] serializedVersion1 = new byte[] {
1, /* PersistentData.VERSION_1 */
- 2, /* PersistentData.TYPE_SP */
+ 1, /* PersistentData.TYPE_SP */
0x00, 0x00, 0x04, 0x0A, /* SOME_USER_ID */
0x00, 0x03, 0x00, 0x00, /* PASSWORD_NUMERIC_COMPLEX */
1, 2, -1, -2, 33, /* PAYLOAD */
@@ -385,9 +385,8 @@
// Make sure the constants we use on the wire do not change.
assertEquals(0, PersistentData.TYPE_NONE);
- assertEquals(1, PersistentData.TYPE_GATEKEEPER);
- assertEquals(2, PersistentData.TYPE_SP);
- assertEquals(3, PersistentData.TYPE_SP_WEAVER);
+ assertEquals(1, PersistentData.TYPE_SP);
+ assertEquals(2, PersistentData.TYPE_SP_WEAVER);
}
public void testCredentialHash_serializeUnserialize() {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9c712f4..50fab5d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1495,6 +1495,17 @@
public static final String IMSI_KEY_EXPIRATION_DAYS_TIME_INT =
"imsi_key_expiration_days_time_int";
+ /**
+ * Key identifying if the CDMA Caller ID presentation and suppression MMI codes
+ * should be converted to 3GPP CLIR codes when a multimode (CDMA+UMTS+LTE) device is roaming
+ * on a 3GPP network. Specifically *67<number> will be converted to #31#<number> and
+ * *82<number> will be converted to *31#<number> before dialing a call when this key is
+ * set TRUE and device is roaming on a 3GPP network.
+ * @hide
+ */
+ public static final String KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL =
+ "convert_cdma_caller_id_mmi_codes_while_roaming_on_3gpp_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -1745,10 +1756,10 @@
sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
sDefaults.putInt(IMSI_KEY_EXPIRATION_DAYS_TIME_INT, IMSI_ENCRYPTION_DAYS_TIME_DISABLED);
sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
+ sDefaults.putBoolean(KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL,
+ false);
sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_ROAMING_OPERATOR_STRING_ARRAY, null);
- sDefaults.putInt(IMSI_KEY_EXPIRATION_DAYS_TIME_INT, IMSI_ENCRYPTION_DAYS_TIME_DISABLED);
- sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
}
/**
diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadManager.java
index 5fa6a95..4eeabb0 100644
--- a/telephony/java/android/telephony/MbmsDownloadManager.java
+++ b/telephony/java/android/telephony/MbmsDownloadManager.java
@@ -288,13 +288,11 @@
*
* This may throw an {@link MbmsException} containing one of the following errors:
* {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
- * {@link MbmsException#ERROR_SERVICE_LOST}
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
*
* Asynchronous error codes via the {@link MbmsDownloadManagerCallback#error(int, String)}
* callback can include any of the errors except:
- * {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}
- * {@link MbmsException#ERROR_END_OF_SESSION}
+ * {@link MbmsException.StreamingErrors#ERROR_UNABLE_TO_START_SERVICE}
*
* @param classList A list of service classes which the app wishes to receive
* {@link IMbmsDownloadManagerCallback#fileServicesUpdated(List)} callbacks
@@ -315,7 +313,7 @@
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
@@ -334,7 +332,7 @@
* Before calling this method, the app must cancel all of its pending
* {@link DownloadRequest}s via {@link #cancelDownload(DownloadRequest)}. If this is not done,
* an {@link MbmsException} will be thrown with code
- * {@link MbmsException#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT}
+ * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT}
*
* The {@link File} supplied as a root temp file directory must already exist. If not, an
* {@link IllegalArgumentException} will be thrown.
@@ -366,7 +364,7 @@
}
} catch (RemoteException e) {
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
SharedPreferences prefs = mContext.getSharedPreferences(
@@ -417,29 +415,36 @@
downloadService.download(request, callback);
} catch (RemoteException e) {
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
/**
- * Returns a list DownloadRequests that originated from this application (UID).
- *
- * May throw a RemoteException.
- *
- * Asynchronous errors through the listener include any of the errors except
- * <li>ERROR_UNABLED_TO_START_SERVICE</li>
- * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
- * <li>ERROR_MSDC_END_OF_SESSION</li>
+ * Returns a list of pending {@link DownloadRequest}s that originated from this application.
+ * A pending request is one that was issued via
+ * {@link #download(DownloadRequest, IDownloadCallback)} but not cancelled through
+ * {@link #cancelDownload(DownloadRequest)}.
+ * @return A list, possibly empty, of {@link DownloadRequest}s
*/
- public List<DownloadRequest> listPendingDownloads() {
- return null;
+ public @NonNull List<DownloadRequest> listPendingDownloads() throws MbmsException {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ }
+
+ try {
+ return downloadService.listPendingDownloads(mSubscriptionId);
+ } catch (RemoteException e) {
+ mService.set(null);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ }
}
/**
* Attempts to cancel the specified {@link DownloadRequest}.
*
* If the middleware is not aware of the specified download request, an MbmsException will be
- * thrown with error code {@link MbmsException#ERROR_UNKNOWN_DOWNLOAD_REQUEST}.
+ * thrown with error code {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}.
*
* If this method returns without throwing an exception, you may assume that cancellation
* was successful.
@@ -458,7 +463,7 @@
}
} catch (RemoteException e) {
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
deleteDownloadRequestToken(downloadRequest);
}
@@ -486,27 +491,43 @@
return downloadService.getDownloadStatus(downloadRequest, fileInfo);
} catch (RemoteException e) {
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
/**
- * Resets middleware knowledge regarding this download request.
+ * Resets the middleware's knowledge of previously-downloaded files in this download request.
*
- * This state consists of knowledge of what files have already been downloaded.
- * Normally the middleware won't download files who's hash matches previously downloaded
- * content, even if that content has since been deleted. If this function is called
- * repeated content will be downloaded again when available. This does not interrupt
- * in-progress downloads.
+ * Normally, the middleware keeps track of the hashes of downloaded files and won't re-download
+ * files whose server-reported hash matches one of the already-downloaded files. This means
+ * that if the file is accidentally deleted by the user or by the app, the middleware will
+ * not try to download it again.
+ * This method will reset the middleware's cache of hashes for the provided
+ * {@link DownloadRequest}, so that previously downloaded content will be downloaded again
+ * when available.
+ * This will not interrupt in-progress downloads.
*
- * May throw an IllegalArgumentException or RemoteException.
+ * If the middleware is not aware of the specified download request, an MbmsException will be
+ * thrown with error code {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}.
*
- * <li>SUCCESS</li>
- * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
- * <li>ERROR_MSDC_UNKNOWN_REQUEST</li>
+ * May throw a {@link MbmsException} with error code
+ * @param downloadRequest The request to re-download files for.
*/
- public int resetDownloadKnowledge(DownloadRequest downloadRequest) {
- return 0;
+ public void resetDownloadKnowledge(DownloadRequest downloadRequest) throws MbmsException {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ }
+
+ try {
+ int result = downloadService.resetDownloadKnowledge(downloadRequest);
+ if (result != MbmsException.SUCCESS) {
+ throw new MbmsException(result);
+ }
+ } catch (RemoteException e) {
+ mService.set(null);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ }
}
public void dispose() {
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
index 8cc447e..5b3503a 100644
--- a/telephony/java/android/telephony/MbmsStreamingManager.java
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -35,7 +35,10 @@
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-/** @hide */
+/**
+ * This class provides functionality for streaming media over MBMS.
+ * @hide
+ */
public class MbmsStreamingManager {
private static final String LOG_TAG = "MbmsStreamingManager";
public static final String MBMS_STREAMING_SERVICE_ACTION =
@@ -88,6 +91,8 @@
/**
* Terminates this instance, ending calls to the registered listener. Also terminates
* any streaming services spawned from this instance.
+ *
+ * May throw an {@link IllegalStateException}
*/
public void dispose() {
IMbmsStreamingService streamingService = mService.get();
@@ -111,15 +116,15 @@
*
* Multiple calls replace the list of serviceClasses of interest.
*
- * This may throw an {@link MbmsException} containing one of the following errors:
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
- * {@link MbmsException#ERROR_SERVICE_LOST}
+ * This may throw an {@link MbmsException} containing any error in
+ * {@link android.telephony.mbms.MbmsException.GeneralErrors},
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}, or
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}.
*
- * Asynchronous error codes via the {@link MbmsStreamingManagerCallback#error(int, String)}
- * callback can include any of the errors except:
- * {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}
- * {@link MbmsException#ERROR_END_OF_SESSION}
+ * May also throw an unchecked {@link IllegalArgumentException} or an
+ * {@link IllegalStateException}
+ *
+ * @param classList A list of streaming service classes that the app would like updates on.
*/
public void getStreamingServices(List<String> classList) throws MbmsException {
IMbmsStreamingService streamingService = mService.get();
@@ -134,7 +139,7 @@
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
@@ -145,14 +150,21 @@
* reported via
* {@link android.telephony.mbms.StreamingServiceCallback#streamStateUpdated(int, int)}
*
- * May throw an {@link MbmsException} containing any of the following error codes:
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
- * {@link MbmsException#ERROR_SERVICE_LOST}
+ * May throw an
+ * {@link MbmsException} containing any of the error codes in
+ * {@link android.telephony.mbms.MbmsException.GeneralErrors},
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}, or
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}.
*
* May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
- * Asynchronous errors through the listener include any of the errors
+ * Asynchronous errors through the listener include any of the errors in
+ * {@link android.telephony.mbms.MbmsException.GeneralErrors} or
+ * {@link android.telephony.mbms.MbmsException.StreamingErrors}.
+ *
+ * @param serviceInfo The information about the service to stream.
+ * @param listener A listener that'll be called when something about the stream changes.
+ * @return An instance of {@link StreamingService} through which the stream can be controlled.
*/
public StreamingService startStreaming(StreamingServiceInfo serviceInfo,
StreamingServiceCallback listener) throws MbmsException {
@@ -170,7 +182,7 @@
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
return new StreamingService(mSubscriptionId, streamingService, serviceInfo, listener);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 0d1764b..89c9134 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.net.INetworkPolicyManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
@@ -37,6 +38,7 @@
import com.android.internal.telephony.PhoneConstants;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -1539,4 +1541,39 @@
}
return false;
}
+
+ /** {@pending} */
+ public @NonNull List<SubscriptionPlan> getSubscriptionPlans(int subId) {
+ final INetworkPolicyManager npm = INetworkPolicyManager.Stub
+ .asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+ try {
+ return Arrays.asList(npm.getSubscriptionPlans(subId,
+ mContext.getOpPackageName()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** {@pending} */
+ public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) {
+ final INetworkPolicyManager npm = INetworkPolicyManager.Stub
+ .asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+ try {
+ npm.setSubscriptionPlans(subId, plans.toArray(new SubscriptionPlan[plans.size()]),
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** {@hide} */
+ public String getSubscriptionPlanOwner(int subId) {
+ final INetworkPolicyManager npm = INetworkPolicyManager.Stub
+ .asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+ try {
+ return npm.getSubscriptionPlanOwner(subId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/telephony/java/android/telephony/SubscriptionPlan.aidl b/telephony/java/android/telephony/SubscriptionPlan.aidl
new file mode 100755
index 0000000..655df3a
--- /dev/null
+++ b/telephony/java/android/telephony/SubscriptionPlan.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.telephony;
+
+parcelable SubscriptionPlan;
diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/telephony/java/android/telephony/SubscriptionPlan.java
new file mode 100644
index 0000000..da7661ae
--- /dev/null
+++ b/telephony/java/android/telephony/SubscriptionPlan.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2017 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.telephony;
+
+import android.annotation.BytesLong;
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.net.NetworkPolicy;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalUnit;
+import java.util.Iterator;
+
+/** {@pending} */
+public final class SubscriptionPlan implements Parcelable {
+ private static final String TAG = "SubscriptionPlan";
+ private static final boolean DEBUG = false;
+
+ /** {@hide} */
+ @IntDef(prefix = "TYPE_", value = {
+ TYPE_NONRECURRING,
+ TYPE_RECURRING_WEEKLY,
+ TYPE_RECURRING_MONTHLY,
+ TYPE_RECURRING_DAILY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ public static final int TYPE_NONRECURRING = 0;
+ public static final int TYPE_RECURRING_MONTHLY = 1;
+ public static final int TYPE_RECURRING_WEEKLY = 2;
+ public static final int TYPE_RECURRING_DAILY = 3;
+
+ /** {@hide} */
+ @IntDef(prefix = "LIMIT_BEHAVIOR_", value = {
+ LIMIT_BEHAVIOR_UNKNOWN,
+ LIMIT_BEHAVIOR_DISABLED,
+ LIMIT_BEHAVIOR_BILLED,
+ LIMIT_BEHAVIOR_THROTTLED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LimitBehavior {}
+
+ public static final int LIMIT_BEHAVIOR_UNKNOWN = -1;
+ public static final int LIMIT_BEHAVIOR_DISABLED = 0;
+ public static final int LIMIT_BEHAVIOR_BILLED = 1;
+ public static final int LIMIT_BEHAVIOR_THROTTLED = 2;
+
+ public static final long BYTES_UNKNOWN = -1;
+ public static final long TIME_UNKNOWN = -1;
+
+ private final int type;
+ private final ZonedDateTime start;
+ private final ZonedDateTime end;
+ private CharSequence title;
+ private CharSequence summary;
+ private long dataWarningBytes = BYTES_UNKNOWN;
+ private long dataWarningSnoozeTime = TIME_UNKNOWN;
+ private long dataLimitBytes = BYTES_UNKNOWN;
+ private long dataLimitSnoozeTime = TIME_UNKNOWN;
+ private int dataLimitBehavior = LIMIT_BEHAVIOR_UNKNOWN;
+ private long dataUsageBytes = BYTES_UNKNOWN;
+ private long dataUsageTime = TIME_UNKNOWN;
+
+ private SubscriptionPlan(@Type int type, ZonedDateTime start, ZonedDateTime end) {
+ this.type = type;
+ this.start = start;
+ this.end = end;
+ }
+
+ private SubscriptionPlan(Parcel source) {
+ type = source.readInt();
+ if (source.readInt() != 0) {
+ start = ZonedDateTime.parse(source.readString());
+ } else {
+ start = null;
+ }
+ if (source.readInt() != 0) {
+ end = ZonedDateTime.parse(source.readString());
+ } else {
+ end = null;
+ }
+ title = source.readCharSequence();
+ summary = source.readCharSequence();
+ dataWarningBytes = source.readLong();
+ dataWarningSnoozeTime = source.readLong();
+ dataLimitBytes = source.readLong();
+ dataLimitSnoozeTime = source.readLong();
+ dataLimitBehavior = source.readInt();
+ dataUsageBytes = source.readLong();
+ dataUsageTime = source.readLong();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(type);
+ if (start != null) {
+ dest.writeInt(1);
+ dest.writeString(start.toString());
+ } else {
+ dest.writeInt(0);
+ }
+ if (end != null) {
+ dest.writeInt(1);
+ dest.writeString(end.toString());
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeCharSequence(title);
+ dest.writeCharSequence(summary);
+ dest.writeLong(dataWarningBytes);
+ dest.writeLong(dataWarningSnoozeTime);
+ dest.writeLong(dataLimitBytes);
+ dest.writeLong(dataLimitSnoozeTime);
+ dest.writeInt(dataLimitBehavior);
+ dest.writeLong(dataUsageBytes);
+ dest.writeLong(dataUsageTime);
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("SubscriptionPlan:")
+ .append(" type=").append(type)
+ .append(" start=").append(start)
+ .append(" end=").append(end)
+ .append(" title=").append(title)
+ .append(" summary=").append(summary)
+ .append(" dataWarningBytes=").append(dataWarningBytes)
+ .append(" dataWarningSnoozeTime=").append(dataWarningSnoozeTime)
+ .append(" dataLimitBytes=").append(dataLimitBytes)
+ .append(" dataLimitSnoozeTime=").append(dataLimitSnoozeTime)
+ .append(" dataLimitBehavior=").append(dataLimitBehavior)
+ .append(" dataUsageBytes=").append(dataUsageBytes)
+ .append(" dataUsageTime=").append(dataUsageTime)
+ .toString();
+ }
+
+ public static final Parcelable.Creator<SubscriptionPlan> CREATOR = new Parcelable.Creator<SubscriptionPlan>() {
+ @Override
+ public SubscriptionPlan createFromParcel(Parcel source) {
+ return new SubscriptionPlan(source);
+ }
+
+ @Override
+ public SubscriptionPlan[] newArray(int size) {
+ return new SubscriptionPlan[size];
+ }
+ };
+
+ public @Type int getType() {
+ return type;
+ }
+
+ public ZonedDateTime getStart() {
+ return start;
+ }
+
+ public ZonedDateTime getEnd() {
+ return end;
+ }
+
+ public @Nullable CharSequence getTitle() {
+ return title;
+ }
+
+ public @Nullable CharSequence getSummary() {
+ return summary;
+ }
+
+ public @BytesLong long getDataWarningBytes() {
+ return dataWarningBytes;
+ }
+
+ public @BytesLong long getDataLimitBytes() {
+ return dataLimitBytes;
+ }
+
+ public @LimitBehavior int getDataLimitBehavior() {
+ return dataLimitBehavior;
+ }
+
+ public @BytesLong long getDataUsageBytes() {
+ return dataUsageBytes;
+ }
+
+ public @CurrentTimeMillisLong long getDataUsageTime() {
+ return dataUsageTime;
+ }
+
+ /** {@hide} */
+ @VisibleForTesting
+ public static long sNowOverride = -1;
+
+ private static ZonedDateTime now(ZoneId zone) {
+ return (sNowOverride != -1)
+ ? ZonedDateTime.ofInstant(Instant.ofEpochMilli(sNowOverride), zone)
+ : ZonedDateTime.now(zone);
+ }
+
+ /** {@hide} */
+ public static SubscriptionPlan convert(NetworkPolicy policy) {
+ final ZoneId zone = ZoneId.of(policy.cycleTimezone);
+ final ZonedDateTime now = now(zone);
+ final Builder builder;
+ if (policy.cycleDay != NetworkPolicy.CYCLE_NONE) {
+ // Assume we started last January, since it has all possible days
+ ZonedDateTime start = ZonedDateTime.of(
+ now.toLocalDate().minusYears(1).withMonth(1).withDayOfMonth(policy.cycleDay),
+ LocalTime.MIDNIGHT, zone);
+ builder = Builder.createRecurringMonthly(start);
+ } else {
+ Log.w(TAG, "Cycle not defined; assuming last 4 weeks non-recurring");
+ ZonedDateTime end = now;
+ ZonedDateTime start = end.minusWeeks(4);
+ builder = Builder.createNonrecurring(start, end);
+ }
+ if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) {
+ builder.setDataWarning(policy.warningBytes);
+ }
+ if (policy.lastWarningSnooze != NetworkPolicy.SNOOZE_NEVER) {
+ builder.setDataWarningSnooze(policy.lastWarningSnooze);
+ }
+ if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
+ builder.setDataLimit(policy.limitBytes, LIMIT_BEHAVIOR_DISABLED);
+ }
+ if (policy.lastLimitSnooze != NetworkPolicy.SNOOZE_NEVER) {
+ builder.setDataLimitSnooze(policy.lastLimitSnooze);
+ }
+ return builder.build();
+ }
+
+ /** {@hide} */
+ public static NetworkPolicy convert(SubscriptionPlan plan) {
+ final NetworkPolicy policy = new NetworkPolicy();
+ switch (plan.type) {
+ case TYPE_RECURRING_MONTHLY:
+ policy.cycleDay = plan.start.getDayOfMonth();
+ policy.cycleTimezone = plan.start.getZone().getId();
+ break;
+ default:
+ policy.cycleDay = NetworkPolicy.CYCLE_NONE;
+ policy.cycleTimezone = "UTC";
+ break;
+ }
+ policy.warningBytes = plan.dataWarningBytes;
+ policy.limitBytes = plan.dataLimitBytes;
+ policy.lastWarningSnooze = plan.dataWarningSnoozeTime;
+ policy.lastLimitSnooze = plan.dataLimitSnoozeTime;
+ policy.metered = true;
+ policy.inferred = false;
+ return policy;
+ }
+
+ /** {@hide} */
+ public TemporalUnit getTemporalUnit() {
+ switch (type) {
+ case TYPE_RECURRING_DAILY: return ChronoUnit.DAYS;
+ case TYPE_RECURRING_WEEKLY: return ChronoUnit.WEEKS;
+ case TYPE_RECURRING_MONTHLY: return ChronoUnit.MONTHS;
+ default: throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Return an iterator that returns data usage cycles.
+ * <p>
+ * For recurring plans, it starts at the currently active cycle, and then
+ * walks backwards in time through each previous cycle, back to the defined
+ * starting point and no further.
+ * <p>
+ * For non-recurring plans, it returns one single cycle.
+ */
+ public Iterator<Pair<ZonedDateTime, ZonedDateTime>> cycleIterator() {
+ switch (type) {
+ case TYPE_NONRECURRING:
+ return new NonrecurringIterator();
+ case TYPE_RECURRING_WEEKLY:
+ case TYPE_RECURRING_MONTHLY:
+ case TYPE_RECURRING_DAILY:
+ return new RecurringIterator();
+ default:
+ throw new IllegalStateException("Unknown type: " + type);
+ }
+ }
+
+ private class NonrecurringIterator implements Iterator<Pair<ZonedDateTime, ZonedDateTime>> {
+ boolean hasNext = true;
+
+ @Override
+ public boolean hasNext() {
+ return hasNext;
+ }
+
+ @Override
+ public Pair<ZonedDateTime, ZonedDateTime> next() {
+ hasNext = false;
+ return new Pair<>(start, end);
+ }
+ }
+
+ private class RecurringIterator implements Iterator<Pair<ZonedDateTime, ZonedDateTime>> {
+ TemporalUnit unit;
+ long i;
+ ZonedDateTime cycleStart;
+ ZonedDateTime cycleEnd;
+
+ public RecurringIterator() {
+ final ZonedDateTime now = now(start.getZone());
+ if (DEBUG) Log.d(TAG, "Resolving using now " + now);
+
+ unit = getTemporalUnit();
+ i = unit.between(start, now);
+ updateCycle();
+
+ // Walk forwards until we find first cycle after now
+ while (cycleEnd.toEpochSecond() <= now.toEpochSecond()) {
+ i++;
+ updateCycle();
+ }
+
+ // Walk backwards until we find first cycle before now
+ while (cycleStart.toEpochSecond() > now.toEpochSecond()) {
+ i--;
+ updateCycle();
+ }
+ }
+
+ private void updateCycle() {
+ cycleStart = roundBoundaryTime(start.plus(i, unit));
+ cycleEnd = roundBoundaryTime(start.plus(i + 1, unit));
+ }
+
+ private ZonedDateTime roundBoundaryTime(ZonedDateTime boundary) {
+ if ((type == TYPE_RECURRING_MONTHLY)
+ && (boundary.getDayOfMonth() < start.getDayOfMonth())) {
+ // When forced to end a monthly cycle early, we want to count
+ // that entire day against the boundary.
+ return ZonedDateTime.of(boundary.toLocalDate(), LocalTime.MAX, start.getZone());
+ } else {
+ return boundary;
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ return cycleStart.toEpochSecond() >= start.toEpochSecond();
+ }
+
+ @Override
+ public Pair<ZonedDateTime, ZonedDateTime> next() {
+ if (DEBUG) Log.d(TAG, "Cycle " + i + " from " + cycleStart + " to " + cycleEnd);
+ Pair<ZonedDateTime, ZonedDateTime> p = new Pair<>(cycleStart, cycleEnd);
+ i--;
+ updateCycle();
+ return p;
+ }
+ }
+
+ public static class Builder {
+ private final SubscriptionPlan plan;
+
+ private Builder(@Type int type, ZonedDateTime start, ZonedDateTime end) {
+ plan = new SubscriptionPlan(type, start, end);
+ }
+
+ public static Builder createNonrecurring(ZonedDateTime start, ZonedDateTime end) {
+ if (!end.isAfter(start)) {
+ throw new IllegalArgumentException(
+ "End " + end + " isn't after start " + start);
+ }
+ return new Builder(TYPE_NONRECURRING, start, end);
+ }
+
+ public static Builder createRecurringMonthly(ZonedDateTime start) {
+ return new Builder(TYPE_RECURRING_MONTHLY, start, null);
+ }
+
+ public static Builder createRecurringWeekly(ZonedDateTime start) {
+ return new Builder(TYPE_RECURRING_WEEKLY, start, null);
+ }
+
+ public static Builder createRecurringDaily(ZonedDateTime start) {
+ return new Builder(TYPE_RECURRING_DAILY, start, null);
+ }
+
+ public SubscriptionPlan build() {
+ return plan;
+ }
+
+ public Builder setTitle(@Nullable CharSequence title) {
+ plan.title = title;
+ return this;
+ }
+
+ public Builder setSummary(@Nullable CharSequence summary) {
+ plan.summary = summary;
+ return this;
+ }
+
+ public Builder setDataWarning(@BytesLong long dataWarningBytes) {
+ if (dataWarningBytes < BYTES_UNKNOWN) {
+ throw new IllegalArgumentException("Warning must be positive or BYTES_UNKNOWN");
+ }
+ plan.dataWarningBytes = dataWarningBytes;
+ return this;
+ }
+
+ /** {@hide} */
+ public Builder setDataWarningSnooze(@CurrentTimeMillisLong long dataWarningSnoozeTime) {
+ plan.dataWarningSnoozeTime = dataWarningSnoozeTime;
+ return this;
+ }
+
+ public Builder setDataLimit(@BytesLong long dataLimitBytes,
+ @LimitBehavior int dataLimitBehavior) {
+ if (dataLimitBytes < BYTES_UNKNOWN) {
+ throw new IllegalArgumentException("Limit must be positive or BYTES_UNKNOWN");
+ }
+ plan.dataLimitBytes = dataLimitBytes;
+ plan.dataLimitBehavior = dataLimitBehavior;
+ return this;
+ }
+
+ /** {@hide} */
+ public Builder setDataLimitSnooze(@CurrentTimeMillisLong long dataLimitSnoozeTime) {
+ plan.dataLimitSnoozeTime = dataLimitSnoozeTime;
+ return this;
+ }
+
+ public Builder setDataUsage(@BytesLong long dataUsageBytes,
+ @CurrentTimeMillisLong long dataUsageTime) {
+ if (dataUsageBytes < BYTES_UNKNOWN) {
+ throw new IllegalArgumentException("Usage must be positive or BYTES_UNKNOWN");
+ }
+ if (dataUsageTime < TIME_UNKNOWN) {
+ throw new IllegalArgumentException("Time must be positive or TIME_UNKNOWN");
+ }
+ if ((dataUsageBytes == BYTES_UNKNOWN) != (dataUsageTime == TIME_UNKNOWN)) {
+ throw new IllegalArgumentException("Must provide both usage and time or neither");
+ }
+ plan.dataUsageBytes = dataUsageBytes;
+ plan.dataUsageTime = dataUsageTime;
+ return this;
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
index 8116a7f..007aee7 100755
--- a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
@@ -30,7 +30,5 @@
void streamingServicesUpdated(in List<StreamingServiceInfo> services);
- void activeStreamingServicesUpdated(in List<StreamingServiceInfo> services);
-
void middlewareReady();
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
index 5b22199..ba25f66 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
@@ -55,7 +55,7 @@
* Before this method is called, calling any method on an instance of
* {@link android.telephony.MbmsDownloadManager} will result in an {@link MbmsException}
* being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * or {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY}
+ * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}
*/
@Override
public void middlewareReady() {
diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java
index e190623..8888119 100644
--- a/telephony/java/android/telephony/mbms/MbmsException.java
+++ b/telephony/java/android/telephony/mbms/MbmsException.java
@@ -18,27 +18,112 @@
/** @hide */
public class MbmsException extends Exception {
+ /** Indicates that the operation was successful. */
public static final int SUCCESS = 0;
- public static final int ERROR_NO_SERVICE_INSTALLED = 1;
- public static final int ERROR_MULTIPLE_SERVICES_INSTALLED = 2;
- public static final int ERROR_BIND_TIMEOUT_OR_FAILURE = 3;
- public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 4;
- public static final int ERROR_ALREADY_INITIALIZED = 5;
- public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 6;
- public static final int ERROR_MIDDLEWARE_NOT_BOUND = 7;
- public static final int ERROR_UNABLE_TO_START_SERVICE = 8;
- public static final int ERROR_STREAM_ALREADY_STARTED = 9;
- public static final int ERROR_END_OF_SESSION = 10;
- public static final int ERROR_SERVICE_LOST = 11;
- public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 12;
- public static final int ERROR_IN_E911 = 13;
- public static final int ERROR_OUT_OF_MEMORY = 14;
- public static final int ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE = 15;
- public static final int ERROR_UNABLE_TO_READ_SIM = 16;
- public static final int ERROR_CARRIER_CHANGE_NOT_ALLOWED = 17;
- public static final int ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT = 18;
- public static final int ERROR_UNKNOWN_DOWNLOAD_REQUEST = 19;
- public static final int ERROR_UNABLE_TO_INITIALIZE = 20;
+
+ // Following errors are generated in the manager and should not be returned from the
+ // middleware
+ /**
+ * Indicates that either no MBMS middleware app is installed on the device or multiple
+ * middleware apps are installed on the device.
+ */
+ public static final int ERROR_NO_UNIQUE_MIDDLEWARE = 1;
+
+ /**
+ * Indicates that the app attempted to perform an operation on an instance of
+ * {@link android.telephony.MbmsDownloadManager} or
+ * {@link android.telephony.MbmsStreamingManager} without being bound to the middleware.
+ */
+ public static final int ERROR_MIDDLEWARE_NOT_BOUND = 2;
+
+ /** Indicates that the middleware has died and the requested operation was not completed.*/
+ public static final int ERROR_MIDDLEWARE_LOST = 3;
+
+ /**
+ * Indicates errors that may be generated during initialization by the
+ * middleware. They are applicable to both streaming and file-download use-cases.
+ */
+ public static class InitializationErrors {
+ /**
+ * Indicates that the app tried to create more than one instance each of
+ * {@link android.telephony.MbmsStreamingManager} or
+ * {@link android.telephony.MbmsDownloadManager}.
+ */
+ public static final int ERROR_DUPLICATE_INITIALIZE = 101;
+ /** Indicates that the app is not authorized to access media via MBMS.*/
+ public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 102;
+ /** Indicates that the middleware was unable to initialize for this app. */
+ public static final int ERROR_UNABLE_TO_INITIALIZE = 103;
+ }
+
+ /**
+ * Indicates the errors that may occur at any point and are applicable to both
+ * streaming and file-download.
+ */
+ public static class GeneralErrors {
+ /**
+ * Indicates that the app attempted to perform an operation before receiving notification
+ * that the middleware is ready via {@link MbmsStreamingManagerCallback#middlewareReady()}
+ * or {@link MbmsDownloadManagerCallback#middlewareReady()}.
+ */
+ public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 201;
+ /**
+ * Indicates that the middleware ran out of memory and was unable to complete the requested
+ * operation.
+ */
+ public static final int ERROR_OUT_OF_MEMORY = 202;
+ /**
+ * Indicates that the requested operation failed due to the middleware being unavailable due
+ * to a transient condition. The app may retry the operation at a later time.
+ */
+ public static final int ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE = 203;
+ /**
+ * Indicates that the requested operation was not performed due to being in emergency
+ * callback mode.
+ */
+ public static final int ERROR_IN_E911 = 204;
+ /** Indicates that MBMS is not available due to the device being in roaming. */
+ public static final int ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE = 205;
+ /** Indicates that MBMS is not available due to a SIM read error. */
+ public static final int ERROR_UNABLE_TO_READ_SIM = 206;
+ /**
+ * Indicates that MBMS is not available due to the inserted SIM being from an unsupported
+ * carrier.
+ */
+ public static final int ERROR_CARRIER_CHANGE_NOT_ALLOWED = 207;
+ }
+
+ /**
+ * Indicates the errors that are applicable only to the streaming use-case
+ */
+ public static class StreamingErrors {
+ /** Indicates that the middleware cannot start a stream due to too many ongoing streams */
+ public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 301;
+
+ /** Indicates that the middleware was unable to start the streaming service */
+ public static final int ERROR_UNABLE_TO_START_SERVICE = 302;
+
+ /**
+ * Indicates that the app called
+ * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, StreamingServiceCallback)}
+ * more than once for the same {@link StreamingServiceInfo}.
+ */
+ public static final int ERROR_DUPLICATE_START_STREAM = 303;
+ }
+
+ /**
+ * Indicates the errors that are applicable only to the file-download use-case
+ */
+ public static class DownloadErrors {
+ /**
+ * Indicates that the app is not allowed to change the temp file root at this time due to
+ * outstanding download requests.
+ */
+ public static final int ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT = 401;
+
+ /** Indicates that the middleware has no record of the supplied {@link DownloadRequest}. */
+ public static final int ERROR_UNKNOWN_DOWNLOAD_REQUEST = 402;
+ }
private final int mErrorCode;
diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
index 27d9878..2e91be9 100644
--- a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
@@ -50,25 +50,12 @@
}
/**
- * Called to indicate the active Streaming Services have changed.
- *
- * This will be caused whenever a new service starts streaming or whenever
- * MbmsStreamServiceManager.getActiveStreamingServices is called.
- *
- * @param services a list of StreamingServiceInfos. May be empty if
- * there are no active StreamingServices
- */
- public void activeStreamingServicesUpdated(List<StreamingServiceInfo> services) {
- // default implementation empty
- }
-
- /**
* Called to indicate that the middleware has been initialized and is ready.
*
* Before this method is called, calling any method on an instance of
* {@link android.telephony.MbmsStreamingManager} will result in an {@link MbmsException}
* being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * or {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY}
+ * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}
*/
@Override
public void middlewareReady() {
diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java
index 1e03fb9..4b913f8 100644
--- a/telephony/java/android/telephony/mbms/MbmsUtils.java
+++ b/telephony/java/android/telephony/mbms/MbmsUtils.java
@@ -22,14 +22,11 @@
import android.content.ServiceConnection;
import android.content.pm.*;
import android.content.pm.ServiceInfo;
-import android.telephony.MbmsDownloadManager;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
/**
* @hide
@@ -78,7 +75,7 @@
MbmsUtils.getMiddlewareServiceInfo(context, serviceAction);
if (mbmsServiceInfo == null) {
- throw new MbmsException(MbmsException.ERROR_NO_SERVICE_INSTALLED);
+ throw new MbmsException(MbmsException.ERROR_NO_UNIQUE_MIDDLEWARE);
}
bindIntent.setComponent(MbmsUtils.toComponentName(mbmsServiceInfo));
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
index 475c93a..1a64189 100644
--- a/telephony/java/android/telephony/mbms/StreamingService.java
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -18,7 +18,6 @@
import android.annotation.IntDef;
import android.net.Uri;
-import android.os.DeadObjectException;
import android.os.RemoteException;
import android.telephony.mbms.vendor.IMbmsStreamingService;
import android.util.Log;
@@ -50,15 +49,42 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({REASON_BY_USER_REQUEST, REASON_END_OF_SESSION, REASON_FREQUENCY_CONFLICT,
- REASON_OUT_OF_MEMORY, REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE})
+ REASON_OUT_OF_MEMORY, REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE,
+ REASON_LEFT_MBMS_BROADCAST_AREA})
public @interface StreamingStateChangeReason {}
+
+ /**
+ * State changed due to a call to {@link #stopStreaming()} or
+ * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, StreamingServiceCallback)}
+ */
public static final int REASON_BY_USER_REQUEST = 1;
+
+ /**
+ * State changed due to the streaming session ending at the carrier.
+ */
public static final int REASON_END_OF_SESSION = 2;
+
+ /**
+ * State changed due to a frequency conflict with another requested stream.
+ */
public static final int REASON_FREQUENCY_CONFLICT = 3;
+
+ /**
+ * State changed due to the middleware running out of memory
+ */
public static final int REASON_OUT_OF_MEMORY = 4;
+
+ /**
+ * State changed due to the device leaving the home carrier's LTE network.
+ */
public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5;
/**
+ * State changed due to the device leaving the where this stream is being broadcast.
+ */
+ public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 5;
+
+ /**
* The method of transmission currently used for a stream,
* reported via {@link StreamingServiceCallback#streamMethodUpdated}
*/
@@ -87,7 +113,9 @@
* Retreive the Uri used to play this stream.
*
* This may throw a {@link MbmsException} with the error code
- * {@link MbmsException#ERROR_SERVICE_LOST}
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
+ *
+ * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
* @return The {@link Uri} to pass to the streaming client.
*/
@@ -101,7 +129,7 @@
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService = null;
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
@@ -115,7 +143,9 @@
/**
* Stop streaming this service.
* This may throw a {@link MbmsException} with the error code
- * {@link MbmsException#ERROR_SERVICE_LOST}
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
+ *
+ * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*/
public void stopStreaming() throws MbmsException {
if (mService == null) {
@@ -127,10 +157,18 @@
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService = null;
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
+ /**
+ * Disposes of this stream. Further operations on this object will fail with an
+ * {@link IllegalStateException}.
+ *
+ * This may throw a {@link MbmsException} with the error code
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
+ * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+ */
public void dispose() throws MbmsException {
if (mService == null) {
throw new IllegalStateException("No streaming service attached");
@@ -140,8 +178,9 @@
mService.disposeStream(mSubscriptionId, mServiceInfo.getServiceId());
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ } finally {
mService = null;
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
}
}
}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
index 06be8a0..725d11c 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
@@ -24,7 +24,6 @@
import android.telephony.mbms.IDownloadCallback;
/**
- * The interface the opaque MbmsStreamingService will satisfy.
* @hide
*/
interface IMbmsDownloadService
@@ -43,12 +42,7 @@
int getDownloadStatus(in DownloadRequest downloadRequest, in FileInfo fileInfo);
- /*
- * named this for 2 reasons:
- * 1 don't want 'State' here as it conflicts with 'Status' of the previous function
- * 2 want to perfect typing 'Knowledge'
- */
- void resetDownloadKnowledge(in DownloadRequest downloadRequest);
+ int resetDownloadKnowledge(in DownloadRequest downloadRequest);
void dispose(int subId);
}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
index 1370b83..04a53cb 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
@@ -22,12 +22,11 @@
import android.telephony.mbms.StreamingServiceInfo;
/**
- * The interface the opaque MbmsStreamingService will satisfy.
* @hide
*/
interface IMbmsStreamingService
{
- int initialize(IMbmsStreamingManagerCallback listener, int subId);
+ void initialize(IMbmsStreamingManagerCallback listener, int subId);
int getStreamingServices(int subId, in List<String> serviceClasses);
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index 305d387..8fbd448 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -16,6 +16,7 @@
package android.telephony.mbms.vendor;
+import android.annotation.NonNull;
import android.os.RemoteException;
import android.telephony.mbms.DownloadRequest;
import android.telephony.mbms.FileInfo;
@@ -35,7 +36,9 @@
/**
* Initialize the download service for this app and subId, registering the listener.
*
- * May throw an {@link IllegalArgumentException} or a {@link SecurityException}
+ * Exceptions should not be thrown through this method -- this method is called from within a
+ * {@link android.content.ServiceConnection} defined by the framework, so apps have no way of
+ * catching them. Call {@link IMbmsDownloadManagerCallback#error(int, String)} instead.
*
* @param listener The callback to use to communicate with the app.
* @param subscriptionId The subscription ID to use.
@@ -59,9 +62,8 @@
* @param serviceClasses The service classes that the app wishes to get info on. The strings
* may contain arbitrary data as negotiated between the app and the
* carrier.
- * @return One of {@link MbmsException#SUCCESS},
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY},
- * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ * @return One of {@link MbmsException#SUCCESS} or
+ * {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY},
*/
@Override
public int getFileServices(int subscriptionId, List<String> serviceClasses)
@@ -76,14 +78,13 @@
*
* If the calling app (as identified by the calling UID) currently has any pending download
* requests that have not been canceled, the middleware must return
- * {@link MbmsException#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} here.
+ * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} here.
*
* @param subscriptionId The subscription id the download is operating under.
* @param rootDirectoryPath The path to the app's temp file root directory.
* @return {@link MbmsException#SUCCESS},
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY},
- * {@link MbmsException#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT},
- * or {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ * {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} or
+ * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT}
*/
@Override
public int setTempFileRootDirectory(int subscriptionId,
@@ -109,8 +110,18 @@
return 0;
}
+
+ /**
+ * Returns a list of pending {@link DownloadRequest}s that originated from the calling
+ * application, identified by its uid. A pending request is one that was issued via
+ * {@link #download(DownloadRequest, IDownloadCallback)} but not cancelled through
+ * {@link #cancelDownload(DownloadRequest)}.
+ * The middleware must return a non-null result synchronously or throw an exception
+ * inheriting from {@link RuntimeException}.
+ * @return A list, possibly empty, of {@link DownloadRequest}s
+ */
@Override
- public List<DownloadRequest> listPendingDownloads(int subscriptionId)
+ public @NonNull List<DownloadRequest> listPendingDownloads(int subscriptionId)
throws RemoteException {
return null;
}
@@ -124,23 +135,47 @@
* {@link DownloadRequest}.
* @param downloadRequest The request to cancel
* @return {@link MbmsException#SUCCESS},
- * {@link MbmsException#ERROR_UNKNOWN_DOWNLOAD_REQUEST},
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY}
+ * {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST},
+ * {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}
*/
@Override
public int cancelDownload(DownloadRequest downloadRequest) throws RemoteException {
return 0;
}
+ /**
+ * Gets information about the status of a file pending download.
+ *
+ * If the middleware has not yet been properly initialized or if it has no records of the
+ * file indicated by {@code fileInfo} being associated with {@code downloadRequest},
+ * {@link android.telephony.MbmsDownloadManager#STATUS_UNKNOWN} must be returned.
+ *
+ * @param downloadRequest The download request to query.
+ * @param fileInfo The particular file within the request to get information on.
+ * @return The status of the download.
+ */
@Override
public int getDownloadStatus(DownloadRequest downloadRequest, FileInfo fileInfo)
throws RemoteException {
return 0;
}
+ /**
+ * Resets the middleware's knowledge of previously-downloaded files in this download request.
+ *
+ * When this method is called, the middleware must attempt to re-download all the files
+ * specified by the {@link DownloadRequest}, even if the files have not changed on the server.
+ * In addition, current in-progress downloads must not be interrupted.
+ *
+ * If the middleware is not aware of the specified download request, return
+ * {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}.
+ *
+ * @param downloadRequest The request to re-download files for.
+ */
@Override
- public void resetDownloadKnowledge(DownloadRequest downloadRequest)
+ public int resetDownloadKnowledge(DownloadRequest downloadRequest)
throws RemoteException {
+ return 0;
}
/**
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index c97e754..f072c46 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -33,16 +33,17 @@
/**
* Initialize streaming service for this app and subId, registering the listener.
*
- * May throw an {@link IllegalArgumentException} or a {@link SecurityException}
+ * Exceptions should not be thrown through this method -- this method is called from within a
+ * {@link android.content.ServiceConnection} defined by the framework, so apps have no way of
+ * catching them. Call {@link IMbmsStreamingManagerCallback#error(int, String)} instead.
*
* @param listener The callback to use to communicate with the app.
* @param subscriptionId The subscription ID to use.
- * @return {@link MbmsException#SUCCESS} or {@link MbmsException#ERROR_ALREADY_INITIALIZED}
*/
@Override
- public int initialize(IMbmsStreamingManagerCallback listener, int subscriptionId)
+ public void initialize(IMbmsStreamingManagerCallback listener, int subscriptionId)
throws RemoteException {
- return 0;
+ return;
}
/**
@@ -59,9 +60,8 @@
* @param serviceClasses The service classes that the app wishes to get info on. The strings
* may contain arbitrary data as negotiated between the app and the
* carrier.
- * @return One of {@link MbmsException#SUCCESS},
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY},
- * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ * @return {@link MbmsException#SUCCESS} or any of the errors in
+ * {@link android.telephony.mbms.MbmsException.GeneralErrors}
*/
@Override
public int getStreamingServices(int subscriptionId,
@@ -79,8 +79,7 @@
* @param subscriptionId The subscription id to use.
* @param serviceId The ID of the streaming service that the app has requested.
* @param listener The listener object on which the app wishes to receive updates.
- * @return {@link MbmsException#SUCCESS}, {@link MbmsException#ERROR_STREAM_ALREADY_STARTED},
- * or {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}.
+ * @return Any error in {@link android.telephony.mbms.MbmsException.GeneralErrors}
*/
@Override
public int startStreaming(int subscriptionId, String serviceId,
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 9053b23..3c3718a 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -22,9 +22,15 @@
# =====================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := \
+ $(filter-out $(android_test_mock_source_files), $(call all-java-files-under, src))
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework legacy-test
+LOCAL_JAVA_LIBRARIES := \
+ core-oj \
+ core-libart \
+ framework \
+ legacy-test \
+ android.test.mock \
LOCAL_MODULE:= android.test.runner
diff --git a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
index d408b84..6dc9ba7 100644
--- a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
+++ b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
@@ -20,6 +20,7 @@
import android.app.WallpaperColors;
import android.graphics.Color;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.Range;
@@ -42,7 +43,7 @@
@Test
public void extractInto_usesFallback() {
GradientColors normal = new GradientColors();
- Tonal tonal = new Tonal();
+ Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
tonal.extractInto(null, normal, new GradientColors(),
new GradientColors());
assertFalse("Should use fallback color if WallpaperColors is null.",
@@ -52,13 +53,14 @@
@Test
public void extractInto_usesFallbackWhenTooLightOrDark() {
GradientColors normal = new GradientColors();
- Tonal tonal = new Tonal();
+ Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
tonal.extractInto(new WallpaperColors(Color.valueOf(0xff000000), null, null, 0),
normal, new GradientColors(), new GradientColors());
assertTrue("Should use fallback color if WallpaperColors is too dark.",
normal.getMainColor() == Tonal.MAIN_COLOR_DARK);
- tonal.extractInto(new WallpaperColors(Color.valueOf(0xffffffff), null, null, 0),
+ tonal.extractInto(new WallpaperColors(Color.valueOf(0xffffffff), null, null,
+ WallpaperColors.HINT_SUPPORTS_DARK_TEXT),
normal, new GradientColors(), new GradientColors());
assertTrue("Should use fallback color if WallpaperColors is too light.",
normal.getMainColor() == Tonal.MAIN_COLOR_LIGHT);
@@ -89,18 +91,28 @@
}
@Test
- public void colorRange_excludeBlacklistedColor() {
- // Creating a WallpaperColors object that contains *only* blacklisted colors
- float[] hsl = Tonal.BLACKLISTED_COLORS[0].getCenter();
+ public void configParser_dataSanity() {
+ Tonal.ConfigParser config = new Tonal.ConfigParser(InstrumentationRegistry.getContext());
+ // 1 to avoid regression where only first item would be parsed.
+ assertTrue("Tonal palettes are empty", config.getTonalPalettes().size() > 1);
+ assertTrue("Blacklisted colors are empty", config.getBlacklistedColors().size() > 1);
+ }
+
+ @Test
+ public void tonal_excludeBlacklistedColor() {
+ // Make sure that palette generation will fail.
+ Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
+
+ // Creating a WallpaperColors object that contains *only* blacklisted colors.
+ float[] hsl = tonal.getBlacklistedColors().get(0).getCenter();
WallpaperColors colors = new WallpaperColors(Color.valueOf(ColorUtils.HSLToColor(hsl)),
null, null, 0);
// Make sure that palette generation will fail
- Tonal tonal = new Tonal();
GradientColors normal = new GradientColors();
tonal.extractInto(colors, normal, new GradientColors(),
new GradientColors());
- assertFalse("Cannot generate a tonal palette from blacklisted colors.",
- normal.getMainColor() == Tonal.MAIN_COLOR_LIGHT);
+ assertTrue("Cannot generate a tonal palette from blacklisted colors.",
+ normal.getMainColor() == Tonal.MAIN_COLOR_DARK);
}
}
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index d11565a..eff04ab 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -201,9 +201,14 @@
" time_ms: 1",
" transports: 0",
" default_network_event <",
+ " default_network_duration_ms: 0",
+ " final_score: 0",
+ " initial_score: 0",
+ " ip_support: 0",
" network_id <",
" network_id: 102",
" >",
+ " no_default_network_duration_ms: 0",
" previous_network_id <",
" network_id: 101",
" >",
@@ -442,6 +447,8 @@
" program_updates_all: 7",
" program_updates_allowing_multicast: 3",
" received_ras: 10",
+ " total_packet_dropped: 0",
+ " total_packet_processed: 0",
" zero_lifetime_ras: 1",
" >",
">",
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index e01469b..cc18b7f 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -256,9 +256,14 @@
" time_ms: 300",
" transports: 0",
" default_network_event <",
+ " default_network_duration_ms: 0",
+ " final_score: 0",
+ " initial_score: 0",
+ " ip_support: 0",
" network_id <",
" network_id: 102",
" >",
+ " no_default_network_duration_ms: 0",
" previous_network_id <",
" network_id: 101",
" >",
@@ -308,6 +313,8 @@
" program_updates_all: 7",
" program_updates_allowing_multicast: 3",
" received_ras: 10",
+ " total_packet_dropped: 0",
+ " total_packet_processed: 0",
" zero_lifetime_ras: 1",
" >",
">",
@@ -367,6 +374,10 @@
" event_types: 1",
" event_types: 1",
" event_types: 2",
+ " getaddrinfo_error_count: 0",
+ " getaddrinfo_query_count: 0",
+ " gethostbyname_error_count: 0",
+ " gethostbyname_query_count: 0",
" latencies_ms: 3456",
" latencies_ms: 45",
" latencies_ms: 638",
@@ -384,6 +395,10 @@
" dns_lookup_batch <",
" event_types: 1",
" event_types: 2",
+ " getaddrinfo_error_count: 0",
+ " getaddrinfo_query_count: 0",
+ " gethostbyname_error_count: 0",
+ " gethostbyname_query_count: 0",
" latencies_ms: 56",
" latencies_ms: 34",
" return_codes: 0",
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index f98ab3d..46f395e 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -111,6 +111,10 @@
" event_types: 1",
" event_types: 2",
" event_types: 2",
+ " getaddrinfo_error_count: 0",
+ " getaddrinfo_query_count: 0",
+ " gethostbyname_error_count: 0",
+ " gethostbyname_query_count: 0",
" latencies_ms: 3456",
" latencies_ms: 267",
" latencies_ms: 1230",
@@ -142,6 +146,10 @@
" event_types: 2",
" event_types: 1",
" event_types: 1",
+ " getaddrinfo_error_count: 0",
+ " getaddrinfo_query_count: 0",
+ " gethostbyname_error_count: 0",
+ " gethostbyname_query_count: 0",
" latencies_ms: 56",
" latencies_ms: 78",
" latencies_ms: 14",
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index acf9e8f7..a115146 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -178,6 +178,7 @@
mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
mLooper.getLooper(), mSystemProperties,
mTetheringDependencies);
+ verify(mNMService).registerTetheringStatsProvider(any(), anyString());
}
@After
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index 0e4a36c..dcb9723 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -16,26 +16,38 @@
package com.android.server.connectivity.tethering;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.TrafficStats.UID_TETHERING;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
+import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.net.ITetheringStatsProvider;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkStats;
import android.net.RouteInfo;
import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.INetworkManagementService;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -66,11 +78,14 @@
@Mock private OffloadHardwareInterface mHardware;
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
+ @Mock private INetworkManagementService mNMService;
private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
ArgumentCaptor.forClass(ArrayList.class);
+ private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor =
+ ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class);
private MockContentResolver mContentResolver;
- @Before public void setUp() throws Exception {
+ @Before public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
when(mContext.getPackageName()).thenReturn("OffloadControllerTest");
@@ -88,14 +103,23 @@
when(mHardware.initOffloadConfig()).thenReturn(true);
when(mHardware.initOffloadControl(any(OffloadHardwareInterface.ControlCallback.class)))
.thenReturn(true);
+ when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
}
private void enableOffload() {
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
}
+ private OffloadController makeOffloadController() throws Exception {
+ OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()),
+ mHardware, mContentResolver, mNMService, new SharedLog("test"));
+ verify(mNMService).registerTetheringStatsProvider(
+ mTetherStatsProviderCaptor.capture(), anyString());
+ return offload;
+ }
+
@Test
- public void testNoSettingsValueDefaultDisabledDoesNotStart() {
+ public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception {
setupFunctioningHardwareInterface();
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
try {
@@ -103,8 +127,7 @@
fail();
} catch (SettingNotFoundException expected) {}
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -116,7 +139,7 @@
}
@Test
- public void testNoSettingsValueDefaultEnabledDoesStart() {
+ public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception {
setupFunctioningHardwareInterface();
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
try {
@@ -124,8 +147,7 @@
fail();
} catch (SettingNotFoundException expected) {}
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -137,12 +159,11 @@
}
@Test
- public void testSettingsAllowsStart() {
+ public void testSettingsAllowsStart() throws Exception {
setupFunctioningHardwareInterface();
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -154,12 +175,11 @@
}
@Test
- public void testSettingsDisablesStart() {
+ public void testSettingsDisablesStart() throws Exception {
setupFunctioningHardwareInterface();
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1);
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -174,8 +194,7 @@
setupFunctioningHardwareInterface();
enableOffload();
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -240,6 +259,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
inOrder.verifyNoMoreInteractions();
final String ipv4Gateway = "192.0.2.1";
@@ -249,6 +269,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
inOrder.verifyNoMoreInteractions();
final String ipv6Gw1 = "fe80::cafe";
@@ -258,6 +279,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
ArrayList<String> v6gws = mStringArrayCaptor.getValue();
assertEquals(1, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
@@ -270,6 +292,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
v6gws = mStringArrayCaptor.getValue();
assertEquals(2, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
@@ -287,6 +310,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
v6gws = mStringArrayCaptor.getValue();
assertEquals(2, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
@@ -321,6 +345,7 @@
assertEquals(2, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
assertTrue(v6gws.contains(ipv6Gw2));
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
inOrder.verifyNoMoreInteractions();
// Completely identical LinkProperties updates are de-duped.
@@ -331,4 +356,65 @@
anyObject(), anyObject(), anyObject(), anyObject());
inOrder.verifyNoMoreInteractions();
}
+
+ private void assertNetworkStats(String iface, ForwardedStats stats, NetworkStats.Entry entry) {
+ assertEquals(iface, entry.iface);
+ assertEquals(stats.rxBytes, entry.rxBytes);
+ assertEquals(stats.txBytes, entry.txBytes);
+ assertEquals(SET_DEFAULT, entry.set);
+ assertEquals(TAG_NONE, entry.tag);
+ assertEquals(UID_TETHERING, entry.uid);
+ }
+
+ @Test
+ public void testGetForwardedStats() throws Exception {
+ setupFunctioningHardwareInterface();
+ enableOffload();
+
+ final OffloadController offload = makeOffloadController();
+ offload.start();
+
+ final String ethernetIface = "eth1";
+ final String mobileIface = "rmnet_data0";
+
+ ForwardedStats ethernetStats = new ForwardedStats();
+ ethernetStats.rxBytes = 12345;
+ ethernetStats.txBytes = 54321;
+
+ ForwardedStats mobileStats = new ForwardedStats();
+ mobileStats.rxBytes = 999;
+ mobileStats.txBytes = 99999;
+
+ when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats);
+ when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn(mobileStats);
+
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(ethernetIface);
+ offload.setUpstreamLinkProperties(lp);
+
+ lp.setInterfaceName(mobileIface);
+ offload.setUpstreamLinkProperties(lp);
+
+ lp.setInterfaceName(ethernetIface);
+ offload.setUpstreamLinkProperties(lp);
+
+ ethernetStats.rxBytes = 100000;
+ ethernetStats.txBytes = 100000;
+ offload.setUpstreamLinkProperties(null);
+
+ NetworkStats stats = mTetherStatsProviderCaptor.getValue().getTetherStats();
+ assertEquals(2, stats.size());
+
+ NetworkStats.Entry entry = null;
+ int ethernetPosition = ethernetIface.equals(stats.getValues(0, entry).iface) ? 0 : 1;
+ int mobilePosition = 1 - ethernetPosition;
+
+ entry = stats.getValues(mobilePosition, entry);
+ assertNetworkStats(mobileIface, mobileStats, entry);
+
+ ethernetStats.rxBytes = 12345 + 100000;
+ ethernetStats.txBytes = 54321 + 100000;
+ entry = stats.getValues(ethernetPosition, entry);
+ assertNetworkStats(ethernetIface, ethernetStats, entry);
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e7fbe4f..13d54ab 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -245,6 +245,7 @@
* (e.g., {@code 01a243f405}).
*/
public String SSID;
+
/**
* When set, this network configuration entry should only be used when
* associating with the AP having the specified BSSID. The value is
@@ -740,22 +741,58 @@
}
/**
+ * Indicates if the creator of this configuration has expressed that it
+ * should be considered metered.
+ *
+ * @see #isMetered(WifiConfiguration, WifiInfo)
* @hide
- * A hint about whether or not the network represented by this WifiConfiguration
- * is metered. This is hinted at via the meteredHint bit on DHCP results set in
- * {@link com.android.server.wifi.WifiStateMachine}, or via a network score in
- * {@link com.android.server.wifi.ExternalScoreEvaluator}.
*/
@SystemApi
public boolean meteredHint;
+ /** {@hide} */
+ public static final int METERED_OVERRIDE_NONE = 0;
+ /** {@hide} */
+ public static final int METERED_OVERRIDE_METERED = 1;
+ /** {@hide} */
+ public static final int METERED_OVERRIDE_NOT_METERED = 2;
+
/**
+ * Indicates if the end user has expressed an explicit opinion about the
+ * meteredness of this network, such as through the Settings app.
+ * <p>
+ * This should always override any values from {@link #meteredHint} or
+ * {@link WifiInfo#getMeteredHint()}.
+ *
+ * @see #isMetered(WifiConfiguration, WifiInfo)
* @hide
- * Indicates if a user has specified the WifiConfiguration to be metered. Users
- * can toggle if a network is metered within Settings -> Data Usage -> Network
- * Restrictions.
*/
- public boolean meteredOverride;
+ public int meteredOverride = METERED_OVERRIDE_NONE;
+
+ /**
+ * Blend together all the various opinions to decide if the given network
+ * should be considered metered or not.
+ *
+ * @hide
+ */
+ public static boolean isMetered(WifiConfiguration config, WifiInfo info) {
+ boolean metered = false;
+ if (info != null && info.getMeteredHint()) {
+ metered = true;
+ }
+ if (config != null && config.meteredHint) {
+ metered = true;
+ }
+ if (config != null
+ && config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED) {
+ metered = true;
+ }
+ if (config != null
+ && config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_NOT_METERED) {
+ metered = false;
+ }
+ return metered;
+ }
/**
* @hide
@@ -1426,7 +1463,7 @@
didSelfAdd = false;
ephemeral = false;
meteredHint = false;
- meteredOverride = false;
+ meteredOverride = METERED_OVERRIDE_NONE;
useExternalScores = false;
validatedInternetAccess = false;
mIpConfiguration = new IpConfiguration();
@@ -1520,23 +1557,24 @@
sbuf.append(this.numNoInternetAccessReports).append("\n");
}
if (this.updateTime != null) {
- sbuf.append("update ").append(this.updateTime).append("\n");
+ sbuf.append(" update ").append(this.updateTime).append("\n");
}
if (this.creationTime != null) {
- sbuf.append("creation").append(this.creationTime).append("\n");
+ sbuf.append(" creation ").append(this.creationTime).append("\n");
}
if (this.didSelfAdd) sbuf.append(" didSelfAdd");
if (this.selfAdded) sbuf.append(" selfAdded");
if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
if (this.ephemeral) sbuf.append(" ephemeral");
if (this.meteredHint) sbuf.append(" meteredHint");
- if (this.meteredOverride) sbuf.append(" meteredOverride");
if (this.useExternalScores) sbuf.append(" useExternalScores");
if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
- || this.ephemeral || this.meteredHint || this.meteredOverride
- || this.useExternalScores) {
+ || this.ephemeral || this.meteredHint || this.useExternalScores) {
sbuf.append("\n");
}
+ if (this.meteredOverride != METERED_OVERRIDE_NONE) {
+ sbuf.append(" meteredOverride ").append(meteredOverride).append("\n");
+ }
sbuf.append(" KeyMgmt:");
for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
if (this.allowedKeyManagement.get(k)) {
@@ -2062,7 +2100,7 @@
dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
dest.writeInt(ephemeral ? 1 : 0);
dest.writeInt(meteredHint ? 1 : 0);
- dest.writeInt(meteredOverride ? 1 : 0);
+ dest.writeInt(meteredOverride);
dest.writeInt(useExternalScores ? 1 : 0);
dest.writeInt(creatorUid);
dest.writeInt(lastConnectUid);
@@ -2129,7 +2167,7 @@
config.isLegacyPasspointConfig = in.readInt() != 0;
config.ephemeral = in.readInt() != 0;
config.meteredHint = in.readInt() != 0;
- config.meteredOverride = in.readInt() != 0;
+ config.meteredOverride = in.readInt();
config.useExternalScores = in.readInt() != 0;
config.creatorUid = in.readInt();
config.lastConnectUid = in.readInt();
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index e48f7bd..bd25356 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -459,7 +459,13 @@
return mMacAddress != null && !DEFAULT_MAC_ADDRESS.equals(mMacAddress);
}
- /** {@hide} */
+ /**
+ * Indicates if we've dynamically detected this active network connection as
+ * being metered.
+ *
+ * @see WifiConfiguration#isMetered(WifiConfiguration, WifiInfo)
+ * @hide
+ */
public void setMeteredHint(boolean meteredHint) {
mMeteredHint = meteredHint;
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 7173775..598360c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1837,7 +1837,7 @@
}
/**
- * This call will be deprecated and removed in an upcoming release. It is no longer used to
+ * This call is deprecated and removed. It is no longer used to
* start WiFi Tethering. Please use {@link ConnectivityManager#startTethering(int, boolean,
* ConnectivityManager#OnStartTetheringCallback)} if
* the caller has proper permissions. Callers can also use the LocalOnlyHotspot feature for a
@@ -1849,8 +1849,11 @@
* @return {@code false}
*
* @hide
+ * @deprecated This API is nolonger supported.
+ * @removed
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
String packageName = mContext.getOpPackageName();