Merge "Moving Notifications into the status bar panel such that the Z layering works as expected"
diff --git a/api/current.txt b/api/current.txt
index 1e6bf2c..db17542 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -291,6 +291,7 @@
field public static final int allowBackup = 16843392; // 0x1010280
field public static final int allowClearUserData = 16842757; // 0x1010005
field public static final int allowEmbedded = 16843765; // 0x10103f5
+ field public static final int allowExternalStorageSandbox = 16844201; // 0x10105a9
field public static final int allowParallelSyncs = 16843570; // 0x1010332
field public static final int allowSingleTap = 16843353; // 0x1010259
field public static final int allowTaskReparenting = 16843268; // 0x1010204
@@ -11534,107 +11535,107 @@
public abstract class PackageManager {
ctor public PackageManager();
- method @Deprecated public abstract void addPackageToPreferred(String);
- method public abstract boolean addPermission(android.content.pm.PermissionInfo);
- method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo);
- method @Deprecated public abstract void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+ method @Deprecated public abstract void addPackageToPreferred(@NonNull String);
+ method public abstract boolean addPermission(@NonNull android.content.pm.PermissionInfo);
+ method public abstract boolean addPermissionAsync(@NonNull android.content.pm.PermissionInfo);
+ method @Deprecated public abstract void addPreferredActivity(@NonNull android.content.IntentFilter, int, @Nullable android.content.ComponentName[], @NonNull android.content.ComponentName);
method public abstract boolean canRequestPackageInstalls();
- method public abstract String[] canonicalToCurrentPackageNames(String[]);
- method @CheckResult public abstract int checkPermission(String, String);
- method @CheckResult public abstract int checkSignatures(String, String);
+ method public abstract String[] canonicalToCurrentPackageNames(@NonNull String[]);
+ method @CheckResult public abstract int checkPermission(@NonNull String, @NonNull String);
+ method @CheckResult public abstract int checkSignatures(@NonNull String, @NonNull String);
method @CheckResult public abstract int checkSignatures(int, int);
method public abstract void clearInstantAppCookie();
- method @Deprecated public abstract void clearPackagePreferredActivities(String);
- method public abstract String[] currentToCanonicalPackageNames(String[]);
+ method @Deprecated public abstract void clearPackagePreferredActivities(@NonNull String);
+ method public abstract String[] currentToCanonicalPackageNames(@NonNull String[]);
method public abstract void extendVerificationTimeout(int, int, long);
- method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
- method public abstract android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
- method public abstract android.graphics.drawable.Drawable getApplicationBanner(String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Nullable public abstract android.graphics.drawable.Drawable getActivityBanner(@NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Nullable public abstract android.graphics.drawable.Drawable getActivityBanner(@NonNull android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.graphics.drawable.Drawable getActivityIcon(@NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.graphics.drawable.Drawable getActivityIcon(@NonNull android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.content.pm.ActivityInfo getActivityInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Nullable public abstract android.graphics.drawable.Drawable getActivityLogo(@NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Nullable public abstract android.graphics.drawable.Drawable getActivityLogo(@NonNull android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
+ method @Nullable public abstract android.graphics.drawable.Drawable getApplicationBanner(@NonNull android.content.pm.ApplicationInfo);
+ method @Nullable public abstract android.graphics.drawable.Drawable getApplicationBanner(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract int getApplicationEnabledSetting(@NonNull String);
- method public abstract android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
- method public abstract android.graphics.drawable.Drawable getApplicationIcon(String) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.pm.ApplicationInfo getApplicationInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract CharSequence getApplicationLabel(android.content.pm.ApplicationInfo);
- method public abstract android.graphics.drawable.Drawable getApplicationLogo(android.content.pm.ApplicationInfo);
- method public abstract android.graphics.drawable.Drawable getApplicationLogo(String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.graphics.drawable.Drawable getApplicationIcon(@NonNull android.content.pm.ApplicationInfo);
+ method @NonNull public abstract android.graphics.drawable.Drawable getApplicationIcon(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.content.pm.ApplicationInfo getApplicationInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract CharSequence getApplicationLabel(@NonNull android.content.pm.ApplicationInfo);
+ method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull android.content.pm.ApplicationInfo);
+ method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int);
method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
- method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
- method public abstract android.graphics.drawable.Drawable getDrawable(String, @DrawableRes int, android.content.pm.ApplicationInfo);
- method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
+ method @NonNull public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
+ method @Nullable public abstract android.graphics.drawable.Drawable getDrawable(@NonNull String, @DrawableRes int, @Nullable android.content.pm.ApplicationInfo);
+ method @NonNull public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
method @NonNull public java.util.List<android.content.pm.ModuleInfo> getInstalledModules(int);
- method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
- method @Nullable public abstract String getInstallerPackageName(String);
+ method @NonNull public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
+ method @Nullable public abstract String getInstallerPackageName(@NonNull String);
method @NonNull public abstract byte[] getInstantAppCookie();
method public abstract int getInstantAppCookieMaxBytes();
- method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @Nullable public abstract android.content.Intent getLaunchIntentForPackage(@NonNull String);
method @Nullable public abstract android.content.Intent getLeanbackLaunchIntentForPackage(@NonNull String);
- method public android.content.pm.ModuleInfo getModuleInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public android.content.pm.ModuleInfo getModuleInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @Nullable public abstract String getNameForUid(int);
- method public android.content.pm.PackageInfo getPackageArchiveInfo(String, int);
+ method @Nullable public android.content.pm.PackageInfo getPackageArchiveInfo(@NonNull String, int);
method public abstract int[] getPackageGids(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract int[] getPackageGids(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.pm.PackageInfo getPackageInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract int[] getPackageGids(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract android.content.pm.PackageInfo getPackageInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract android.content.pm.PackageInfo getPackageInfo(@NonNull android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public abstract android.content.pm.PackageInstaller getPackageInstaller();
- method public abstract int getPackageUid(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract int getPackageUid(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @Nullable public abstract String[] getPackagesForUid(int);
- method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(String[], int);
- method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.pm.PermissionInfo getPermissionInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method @Deprecated public abstract int getPreferredActivities(@NonNull java.util.List<android.content.IntentFilter>, @NonNull java.util.List<android.content.ComponentName>, String);
- method @Deprecated public abstract java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
- method public abstract android.content.pm.ProviderInfo getProviderInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.pm.ActivityInfo getReceiverInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.res.Resources getResourcesForActivity(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.res.Resources getResourcesForApplication(String) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(@NonNull String[], int);
+ method @NonNull public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract android.content.pm.PermissionInfo getPermissionInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated public abstract int getPreferredActivities(@NonNull java.util.List<android.content.IntentFilter>, @NonNull java.util.List<android.content.ComponentName>, @Nullable String);
+ method @Deprecated @NonNull public abstract java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
+ method @NonNull public abstract android.content.pm.ProviderInfo getProviderInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.content.pm.ActivityInfo getReceiverInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.content.res.Resources getResourcesForActivity(@NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.content.res.Resources getResourcesForApplication(@NonNull android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.content.res.Resources getResourcesForApplication(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull public abstract android.content.pm.ServiceInfo getServiceInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
method @Nullable public android.os.Bundle getSuspendedPackageAppExtras();
method public boolean getSyntheticAppDetailsActivityEnabled(@NonNull String);
- method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
- method public abstract String[] getSystemSharedLibraryNames();
- method public abstract CharSequence getText(String, @StringRes int, android.content.pm.ApplicationInfo);
- method public abstract android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
- method public abstract android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
- method public abstract CharSequence getUserBadgedLabel(CharSequence, android.os.UserHandle);
- method public abstract android.content.res.XmlResourceParser getXml(String, @XmlRes int, android.content.pm.ApplicationInfo);
- method public boolean hasSigningCertificate(String, byte[], int);
- method public boolean hasSigningCertificate(int, byte[], int);
- method public abstract boolean hasSystemFeature(String);
- method public abstract boolean hasSystemFeature(String, int);
+ method @NonNull public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
+ method @Nullable public abstract String[] getSystemSharedLibraryNames();
+ method @Nullable public abstract CharSequence getText(@NonNull String, @StringRes int, @Nullable android.content.pm.ApplicationInfo);
+ method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle, @Nullable android.graphics.Rect, int);
+ method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedIcon(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle);
+ method @NonNull public abstract CharSequence getUserBadgedLabel(@NonNull CharSequence, @NonNull android.os.UserHandle);
+ method @Nullable public abstract android.content.res.XmlResourceParser getXml(@NonNull String, @XmlRes int, @Nullable android.content.pm.ApplicationInfo);
+ method public boolean hasSigningCertificate(@NonNull String, @NonNull byte[], int);
+ method public boolean hasSigningCertificate(int, @NonNull byte[], int);
+ method public abstract boolean hasSystemFeature(@NonNull String);
+ method public abstract boolean hasSystemFeature(@NonNull String, int);
method public abstract boolean isInstantApp();
- method public abstract boolean isInstantApp(String);
- method public boolean isPackageSuspended(String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract boolean isInstantApp(@NonNull String);
+ method public boolean isPackageSuspended(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isPackageSuspended();
method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String);
method public abstract boolean isSafeMode();
- method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
- method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(String, int, int);
- method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(String, int);
- method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
- method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(@Nullable android.content.ComponentName, @Nullable android.content.Intent[], android.content.Intent, int);
- method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
- method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
- method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method @Deprecated public abstract void removePackageFromPreferred(String);
- method public abstract void removePermission(String);
- method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
- method public abstract android.content.pm.ProviderInfo resolveContentProvider(String, int);
- method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
+ method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(@NonNull android.content.Intent, int);
+ method @NonNull public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(@Nullable String, int, int);
+ method @NonNull public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(@NonNull String, int);
+ method @Nullable public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(@NonNull android.content.Intent, int);
+ method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(@Nullable android.content.ComponentName, @Nullable android.content.Intent[], @NonNull android.content.Intent, int);
+ method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(@NonNull android.content.Intent, int);
+ method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(@NonNull android.content.Intent, int);
+ method @NonNull public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated public abstract void removePackageFromPreferred(@NonNull String);
+ method public abstract void removePermission(@NonNull String);
+ method @Nullable public abstract android.content.pm.ResolveInfo resolveActivity(@NonNull android.content.Intent, int);
+ method @Nullable public abstract android.content.pm.ProviderInfo resolveContentProvider(@NonNull String, int);
+ method @Nullable public abstract android.content.pm.ResolveInfo resolveService(@NonNull android.content.Intent, int);
method public abstract void setApplicationCategoryHint(@NonNull String, int);
method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setApplicationEnabledSetting(@NonNull String, int, int);
method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setComponentEnabledSetting(@NonNull android.content.ComponentName, int, int);
- method public abstract void setInstallerPackageName(String, String);
+ method public abstract void setInstallerPackageName(@NonNull String, @Nullable String);
method public abstract void updateInstantAppCookie(@Nullable byte[]);
method public abstract void verifyPendingInstall(int, int);
field public static final int CERT_INPUT_RAW_X509 = 0; // 0x0
@@ -23279,6 +23280,7 @@
method @Deprecated public boolean registerRemoteController(android.media.RemoteController);
method @Deprecated public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
method public int requestAudioFocus(@NonNull android.media.AudioFocusRequest);
+ method public void setAllowedCapturePolicy(int);
method @Deprecated public void setBluetoothA2dpOn(boolean);
method public void setBluetoothScoOn(boolean);
method public void setMicrophoneMute(boolean);
@@ -28755,6 +28757,7 @@
method @NonNull public static android.net.DnsResolver getInstance();
method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>);
method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>);
+ method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.InetAddressAnswerCallback);
field public static final int CLASS_IN = 1; // 0x1
field public static final int FLAG_EMPTY = 0; // 0x0
field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
@@ -34657,9 +34660,11 @@
method @NonNull public static java.io.File getRootDirectory();
method @Deprecated public static String getStorageState(java.io.File);
method public static boolean isExternalStorageEmulated();
- method public static boolean isExternalStorageEmulated(java.io.File);
+ method public static boolean isExternalStorageEmulated(@NonNull java.io.File);
method public static boolean isExternalStorageRemovable();
- method public static boolean isExternalStorageRemovable(java.io.File);
+ method public static boolean isExternalStorageRemovable(@NonNull java.io.File);
+ method public static boolean isExternalStorageSandboxed();
+ method public static boolean isExternalStorageSandboxed(@NonNull java.io.File);
field public static String DIRECTORY_ALARMS;
field public static String DIRECTORY_AUDIOBOOKS;
field public static String DIRECTORY_DCIM;
@@ -52311,7 +52316,7 @@
method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
method @Deprecated public int getActions();
method public java.util.List<java.lang.String> getAvailableExtraData();
- method public void getBoundsInParent(android.graphics.Rect);
+ method @Deprecated public void getBoundsInParent(android.graphics.Rect);
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
method public int getChildCount();
@@ -52380,7 +52385,7 @@
method public boolean removeChild(android.view.View, int);
method public void setAccessibilityFocused(boolean);
method public void setAvailableExtraData(java.util.List<java.lang.String>);
- method public void setBoundsInParent(android.graphics.Rect);
+ method @Deprecated public void setBoundsInParent(android.graphics.Rect);
method public void setBoundsInScreen(android.graphics.Rect);
method public void setCanOpenPopup(boolean);
method public void setCheckable(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 48b1385..8ee1e0a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1593,46 +1593,46 @@
}
public abstract class PackageManager {
- method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
+ method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
method public abstract boolean arePermissionsIndividuallyControlled();
- method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(String);
+ method @NonNull public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.pm.ApplicationInfo getApplicationInfoAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public android.content.pm.dex.ArtManager getArtManager();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_SHARED_LIBRARIES) public java.util.List<android.content.pm.SharedLibraryInfo> getDeclaredSharedLibraries(@NonNull String, int);
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
method @Nullable @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public CharSequence getHarmfulAppWarning(@NonNull String);
method @Nullable public String getIncidentReportApproverPackageName();
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract android.graphics.drawable.Drawable getInstantAppIcon(String);
- method public abstract android.content.ComponentName getInstantAppInstallerComponent();
- method public abstract android.content.ComponentName getInstantAppResolverSettingsComponent();
+ method @Nullable public abstract android.content.ComponentName getInstantAppInstallerComponent();
+ method @Nullable public abstract android.content.ComponentName getInstantAppResolverSettingsComponent();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
- method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(String);
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract int getIntentVerificationStatusAsUser(String, int);
- method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle);
+ method @NonNull public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract int getIntentVerificationStatusAsUser(@NonNull String, int);
+ method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] getUnsuspendablePackages(@NonNull String[]);
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- method @Deprecated public abstract int installExistingPackage(String) throws android.content.pm.PackageManager.NameNotFoundException;
- method @Deprecated public abstract int installExistingPackage(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
+ method @Deprecated public abstract int installExistingPackage(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated public abstract int installExistingPackage(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(@NonNull android.content.Intent, int, android.os.UserHandle);
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentActivitiesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProvidersAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentServicesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
- method public abstract void registerDexModule(String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback);
- method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
+ method public abstract void registerDexModule(@NonNull String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback);
+ method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
method @Deprecated public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method public void sendDeviceCustomizationReadyBroadcast();
- method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(String, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(@Nullable String, int);
method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setDistractingPackageRestrictions(@NonNull String[], int);
method @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public void setHarmfulAppWarning(@NonNull String, @Nullable CharSequence);
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable String);
method @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable android.content.pm.SuspendDialogInfo);
method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setSyntheticAppDetailsActivityEnabled(@NonNull String, boolean);
- method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(String, boolean);
- method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(String, int, int);
- method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(String, String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT) public abstract void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
+ method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(@NonNull String, boolean);
+ method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String, int, int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT) public abstract void verifyIntentFilter(int, int, @NonNull java.util.List<java.lang.String>);
field public static final String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS";
field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
diff --git a/api/test-current.txt b/api/test-current.txt
index 6f8f310..7762baa 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -315,7 +315,9 @@
}
public final class NotificationChannel implements android.os.Parcelable {
+ method public boolean isImportanceLockedByCriticalDeviceFunction();
method public boolean isImportanceLockedByOEM();
+ method public void setImportanceLockedByCriticalDeviceFunction(boolean);
method public void setImportanceLockedByOEM(boolean);
}
@@ -661,20 +663,20 @@
public abstract class PackageManager {
method public abstract boolean arePermissionsIndividuallyControlled();
- method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int);
+ method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int);
method @Nullable public String getIncidentReportApproverPackageName();
- method public abstract int getInstallReason(String, @NonNull android.os.UserHandle);
- method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
- method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
+ method public abstract int getInstallReason(@NonNull String, @NonNull android.os.UserHandle);
+ method @NonNull public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
+ method @NonNull @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method @Nullable public abstract String[] getNamesForUids(int[]);
- method public abstract String getPermissionControllerPackageName();
- method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS", "android.permission.GET_RUNTIME_PERMISSIONS"}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle);
+ method @NonNull public abstract String getPermissionControllerPackageName();
+ method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS", "android.permission.GET_RUNTIME_PERMISSIONS"}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method @NonNull public abstract String getServicesSystemSharedLibraryPackageName();
method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
- method public String getWellbeingPackageName();
+ method @Nullable public String getWellbeingPackageName();
method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(String, String, int, int, @NonNull android.os.UserHandle);
+ method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, int, int, @NonNull android.os.UserHandle);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
field public static final int FLAG_PERMISSION_HIDDEN = 1024; // 0x400
diff --git a/cmds/bmgr/Android.bp b/cmds/bmgr/Android.bp
new file mode 100644
index 0000000..b64923b
--- /dev/null
+++ b/cmds/bmgr/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2007 The Android Open Source Project
+//
+
+java_binary {
+ name: "bmgr",
+ wrapper: "bmgr",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/bmgr/Android.mk b/cmds/bmgr/Android.mk
deleted file mode 100644
index d520cf2..0000000
--- a/cmds/bmgr/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2007 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := bmgrlib
-LOCAL_MODULE_STEM := bmgr
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := bmgr
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := bmgr
-LOCAL_REQUIRED_MODULES := bmgrlib
-include $(BUILD_PREBUILT)
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 685c067..b46c9e3 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -31,7 +31,7 @@
namespace incidentd {
const ssize_t BUFFER_SIZE = 16 * 1024; // 16 KB
-const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
+const ssize_t MAX_BUFFER_COUNT = 1536; // 24 MB max
FdBuffer::FdBuffer()
:mBuffer(new EncodedBuffer(BUFFER_SIZE)),
diff --git a/cmds/media/Android.bp b/cmds/media/Android.bp
new file mode 100644
index 0000000..7879c53
--- /dev/null
+++ b/cmds/media/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2013 The Android Open Source Project
+//
+
+java_binary {
+ name: "media",
+ wrapper: "media",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/media/Android.mk b/cmds/media/Android.mk
deleted file mode 100644
index b9451c5..0000000
--- a/cmds/media/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := media_cmd
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := media
-LOCAL_SRC_FILES := media
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/media/media b/cmds/media/media
index 5c0eb2f..8ada914 100755
--- a/cmds/media/media
+++ b/cmds/media/media
@@ -3,5 +3,5 @@
# shell.
#
base=/system
-export CLASSPATH=$base/framework/media_cmd.jar
+export CLASSPATH=$base/framework/media.jar
exec app_process $base/bin com.android.commands.media.Media "$@"
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 8cd409e..017cb6d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -81,7 +81,7 @@
"src/external/StatsPullerManager.cpp",
"src/external/puller_util.cpp",
"src/logd/LogEvent.cpp",
- "src/logd/LogListener.cpp",
+ "src/logd/LogEventQueue.cpp",
"src/matchers/CombinationLogMatchingTracker.cpp",
"src/matchers/EventMatcherWizard.cpp",
"src/matchers/matcher_util.cpp",
@@ -226,6 +226,7 @@
"tests/indexed_priority_queue_test.cpp",
"tests/LogEntryMatcher_test.cpp",
"tests/LogEvent_test.cpp",
+ "tests/log_event/LogEventQueue_test.cpp",
"tests/MetricsManager_test.cpp",
"tests/StatsLogProcessor_test.cpp",
"tests/StatsService_test.cpp",
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 0aacdf2..3bcebd9 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -130,34 +130,36 @@
} \
}
-StatsService::StatsService(const sp<Looper>& handlerLooper)
- : mAnomalyAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
- [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
- if (sc != nullptr) {
- sc->setAnomalyAlarm(timeMillis);
- StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
- }
- },
- [](const sp<IStatsCompanionService>& sc) {
- if (sc != nullptr) {
- sc->cancelAnomalyAlarm();
- StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
- }
- })),
- mPeriodicAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
- [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
- if (sc != nullptr) {
- sc->setAlarmForSubscriberTriggering(timeMillis);
- StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
- }
- },
- [](const sp<IStatsCompanionService>& sc) {
- if (sc != nullptr) {
- sc->cancelAlarmForSubscriberTriggering();
- StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
- }
-
- })) {
+StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQueue> queue)
+ : mAnomalyAlarmMonitor(new AlarmMonitor(
+ MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
+ [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
+ if (sc != nullptr) {
+ sc->setAnomalyAlarm(timeMillis);
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
+ }
+ },
+ [](const sp<IStatsCompanionService>& sc) {
+ if (sc != nullptr) {
+ sc->cancelAnomalyAlarm();
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
+ }
+ })),
+ mPeriodicAlarmMonitor(new AlarmMonitor(
+ MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
+ [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
+ if (sc != nullptr) {
+ sc->setAlarmForSubscriberTriggering(timeMillis);
+ StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
+ }
+ },
+ [](const sp<IStatsCompanionService>& sc) {
+ if (sc != nullptr) {
+ sc->cancelAlarmForSubscriberTriggering();
+ StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
+ }
+ })),
+ mEventQueue(queue) {
mUidMap = UidMap::getInstance();
mPullerManager = new StatsPullerManager();
StatsPuller::SetUidMap(mUidMap);
@@ -199,11 +201,33 @@
mConfigManager->AddListener(mProcessor);
init_system_properties();
+
+ if (mEventQueue != nullptr) {
+ std::thread pushedEventThread([this] { readLogs(); });
+ pushedEventThread.detach();
+ }
}
StatsService::~StatsService() {
}
+/* Runs on a dedicated thread to process pushed events. */
+void StatsService::readLogs() {
+ // Read forever..... long live statsd
+ while (1) {
+ // Block until an event is available.
+ auto event = mEventQueue->waitPop();
+ // Pass it to StatsLogProcess to all configs/metrics
+ // At this point, the LogEventQueue is not blocked, so that the socketListener
+ // can read events from the socket and write to buffer to avoid data drop.
+ mProcessor->OnLogEvent(event.get());
+ // The ShellSubscriber is only used by shell for local debugging.
+ if (mShellSubscriber != nullptr) {
+ mShellSubscriber->onLogEvent(*event);
+ }
+ }
+}
+
void StatsService::init_system_properties() {
mEngBuild = false;
const prop_info* buildType = __system_property_find("ro.build.type");
@@ -1007,6 +1031,7 @@
}
}
+// Test only interface!!!
void StatsService::OnLogEvent(LogEvent* event) {
mProcessor->OnLogEvent(event);
if (mShellSubscriber != nullptr) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 38efa89..929d260 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -22,7 +22,7 @@
#include "anomaly/AlarmMonitor.h"
#include "config/ConfigManager.h"
#include "external/StatsPullerManager.h"
-#include "logd/LogListener.h"
+#include "logd/LogEventQueue.h"
#include "packages/UidMap.h"
#include "shell/ShellSubscriber.h"
#include "statscompanion_util.h"
@@ -52,11 +52,10 @@
using android::hardware::Return;
class StatsService : public BnStatsManager,
- public LogListener,
public IStats,
public IBinder::DeathRecipient {
public:
- StatsService(const sp<Looper>& handlerLooper);
+ StatsService(const sp<Looper>& handlerLooper, std::shared_ptr<LogEventQueue> queue);
virtual ~StatsService();
/** The anomaly alarm registered with AlarmManager won't be updated by less than this. */
@@ -92,7 +91,7 @@
void Terminate();
/**
- * Called by LogReader when there's a log event to process.
+ * Test ONLY interface. In real world, StatsService reads from LogEventQueue.
*/
virtual void OnLogEvent(LogEvent* event);
@@ -283,6 +282,9 @@
*/
void print_cmd_help(int out);
+ /* Runs on its dedicated thread to process pushed stats event from socket. */
+ void readLogs();
+
/**
* Trigger a broadcast.
*/
@@ -415,6 +417,8 @@
sp<ShellSubscriber> mShellSubscriber;
+ std::shared_ptr<LogEventQueue> mEventQueue;
+
FRIEND_TEST(StatsServiceTest, TestAddConfig_simple);
FRIEND_TEST(StatsServiceTest, TestAddConfig_empty);
FRIEND_TEST(StatsServiceTest, TestAddConfig_invalid);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 29100aa..74a4c87 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -50,6 +50,7 @@
const int FIELD_ID_PERIODIC_ALARM_STATS = 12;
const int FIELD_ID_SYSTEM_SERVER_RESTART = 15;
const int FIELD_ID_LOGGER_ERROR_STATS = 16;
+const int FIELD_ID_OVERFLOW = 18;
const int FIELD_ID_ATOM_STATS_TAG = 1;
const int FIELD_ID_ATOM_STATS_COUNT = 2;
@@ -64,6 +65,10 @@
const int FIELD_ID_LOG_LOSS_STATS_UID = 5;
const int FIELD_ID_LOG_LOSS_STATS_PID = 6;
+const int FIELD_ID_OVERFLOW_COUNT = 1;
+const int FIELD_ID_OVERFLOW_MAX_HISTORY = 2;
+const int FIELD_ID_OVERFLOW_MIN_HISTORY = 3;
+
const int FIELD_ID_CONFIG_STATS_UID = 1;
const int FIELD_ID_CONFIG_STATS_ID = 2;
const int FIELD_ID_CONFIG_STATS_CREATION = 3;
@@ -235,6 +240,22 @@
noteDataDropped(key, totalBytes, getWallClockSec());
}
+void StatsdStats::noteEventQueueOverflow(int64_t oldestEventTimestampNs) {
+ lock_guard<std::mutex> lock(mLock);
+
+ mOverflowCount++;
+
+ int64_t history = getElapsedRealtimeNs() - oldestEventTimestampNs;
+
+ if (history > mMaxQueueHistoryNs) {
+ mMaxQueueHistoryNs = history;
+ }
+
+ if (history < mMinQueueHistoryNs) {
+ mMinQueueHistoryNs = history;
+ }
+}
+
void StatsdStats::noteDataDropped(const ConfigKey& key, const size_t totalBytes, int32_t timeSec) {
lock_guard<std::mutex> lock(mLock);
auto it = mConfigStats.find(key);
@@ -534,6 +555,9 @@
mPeriodicAlarmRegisteredStats = 0;
mSystemServerRestartSec.clear();
mLogLossStats.clear();
+ mOverflowCount = 0;
+ mMinQueueHistoryNs = kInt64Max;
+ mMaxQueueHistoryNs = 0;
for (auto& config : mConfigStats) {
config.second->broadcast_sent_time_sec.clear();
config.second->activation_time_sec.clear();
@@ -726,6 +750,9 @@
(long long)loss.mWallClockSec, loss.mCount, loss.mLastError, loss.mLastTag,
loss.mUid, loss.mPid);
}
+
+ dprintf(out, "Event queue overflow: %d; MaxHistoryNs: %lld; MinHistoryNs: %lld\n",
+ mOverflowCount, (long long)mMaxQueueHistoryNs, (long long)mMinQueueHistoryNs);
}
void addConfigStatsToProto(const ConfigStats& configStats, ProtoOutputStream* proto) {
@@ -904,6 +931,16 @@
proto.end(token);
}
+ if (mOverflowCount > 0) {
+ uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_OVERFLOW);
+ proto.write(FIELD_TYPE_INT32 | FIELD_ID_OVERFLOW_COUNT, (int32_t)mOverflowCount);
+ proto.write(FIELD_TYPE_INT64 | FIELD_ID_OVERFLOW_MAX_HISTORY,
+ (long long)mMaxQueueHistoryNs);
+ proto.write(FIELD_TYPE_INT64 | FIELD_ID_OVERFLOW_MIN_HISTORY,
+ (long long)mMinQueueHistoryNs);
+ proto.end(token);
+ }
+
for (const auto& restart : mSystemServerRestartSec) {
proto.write(FIELD_TYPE_INT32 | FIELD_ID_SYSTEM_SERVER_RESTART | FIELD_COUNT_REPEATED,
restart);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 434920e..88ecccc 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -160,6 +160,8 @@
// Max platform atom tag number.
static const int32_t kMaxPlatformAtomTag = 100000;
+ static const int64_t kInt64Max = 0x7fffffffffffffffLL;
+
/**
* Report a new config has been received and report the static stats about the config.
*
@@ -419,6 +421,10 @@
*/
void noteBucketUnknownCondition(int64_t metricId);
+ /* Reports one event has been dropped due to queue overflow, and the oldest event timestamp in
+ * the queue */
+ void noteEventQueueOverflow(int64_t oldestEventTimestampNs);
+
/**
* Reset the historical stats. Including all stats in icebox, and the tracked stats about
* metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
@@ -522,6 +528,17 @@
int32_t mPid;
};
+ // Max of {(now - oldestEventTimestamp) when overflow happens}.
+ // This number is helpful to understand how SLOW statsd can be.
+ int64_t mMaxQueueHistoryNs = 0;
+
+ // Min of {(now - oldestEventTimestamp) when overflow happens}.
+ // This number is helpful to understand how FAST the events floods to statsd.
+ int64_t mMinQueueHistoryNs = kInt64Max;
+
+ // Total number of events that are lost due to queue overflow.
+ int32_t mOverflowCount = 0;
+
// Timestamps when we detect log loss, and the number of logs lost.
std::list<LogLossStats> mLogLossStats;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 2b7dc8d..ca874b5 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -121,6 +121,7 @@
LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) {
mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
mTagId = tagId;
mLogUid = 0;
mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
@@ -251,7 +252,8 @@
mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value(trainInfo.status)));
}
-LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) : LogEvent(tagId, timestampNs, 0) {}
+LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) : LogEvent(tagId, timestampNs, timestampNs) {
+}
LogEvent::LogEvent(int32_t tagId, int64_t timestampNs, int32_t uid) {
mLogdTimestampNs = timestampNs;
diff --git a/cmds/statsd/src/logd/LogEventQueue.cpp b/cmds/statsd/src/logd/LogEventQueue.cpp
new file mode 100644
index 0000000..146464b
--- /dev/null
+++ b/cmds/statsd/src/logd/LogEventQueue.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
+
+#include "LogEventQueue.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::unique_lock;
+using std::unique_ptr;
+
+unique_ptr<LogEvent> LogEventQueue::waitPop() {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ if (mQueue.empty()) {
+ mCondition.wait(lock, [this] { return !this->mQueue.empty(); });
+ }
+
+ unique_ptr<LogEvent> item = std::move(mQueue.front());
+ mQueue.pop();
+
+ return item;
+}
+
+bool LogEventQueue::push(unique_ptr<LogEvent> item, int64_t* oldestTimestampNs) {
+ bool success;
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mQueue.size() < mQueueLimit) {
+ mQueue.push(std::move(item));
+ success = true;
+ } else {
+ // safe operation as queue must not be empty.
+ *oldestTimestampNs = mQueue.front()->GetElapsedTimestampNs();
+ success = false;
+ }
+ }
+
+ mCondition.notify_one();
+ return success;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/logd/LogEventQueue.h b/cmds/statsd/src/logd/LogEventQueue.h
new file mode 100644
index 0000000..b4fd63f
--- /dev/null
+++ b/cmds/statsd/src/logd/LogEventQueue.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "LogEvent.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * A zero copy thread safe queue buffer for producing and consuming LogEvent.
+ */
+class LogEventQueue {
+public:
+ explicit LogEventQueue(size_t maxSize) : mQueueLimit(maxSize){};
+
+ /**
+ * Blocking read one event from the queue.
+ */
+ std::unique_ptr<LogEvent> waitPop();
+
+ /**
+ * Puts a LogEvent ptr to the end of the queue.
+ * Returns false on failure when the queue is full, and output the oldest event timestamp
+ * in the queue.
+ */
+ bool push(std::unique_ptr<LogEvent> event, int64_t* oldestTimestampNs);
+
+private:
+ const size_t mQueueLimit;
+ std::condition_variable mCondition;
+ std::mutex mMutex;
+ std::queue<std::unique_ptr<LogEvent>> mQueue;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/logd/LogListener.h b/cmds/statsd/src/logd/LogListener.h
deleted file mode 100644
index d8b06e9..0000000
--- a/cmds/statsd/src/logd/LogListener.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include "logd/LogEvent.h"
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Callback for LogReader
- */
-class LogListener : public virtual android::RefBase {
-public:
- LogListener();
- virtual ~LogListener();
-
- virtual void OnLogEvent(LogEvent* msg) = 0;
-};
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index eddc86e..68082c2 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -80,8 +80,11 @@
::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/);
+ std::shared_ptr<LogEventQueue> eventQueue =
+ std::make_shared<LogEventQueue>(2000 /*buffer limit. Buffer is NOT pre-allocated*/);
+
// Create the service
- gStatsService = new StatsService(looper);
+ gStatsService = new StatsService(looper, eventQueue);
if (defaultServiceManager()->addService(String16("stats"), gStatsService, false,
IServiceManager::DUMP_FLAG_PRIORITY_NORMAL | IServiceManager::DUMP_FLAG_PROTO)
!= 0) {
@@ -101,13 +104,13 @@
gStatsService->Startup();
- sp<StatsSocketListener> socketListener = new StatsSocketListener(gStatsService);
+ sp<StatsSocketListener> socketListener = new StatsSocketListener(eventQueue);
- ALOGI("using statsd socket");
- // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
- if (socketListener->startListener(600)) {
- exit(1);
- }
+ ALOGI("Statsd starts to listen to socket.");
+ // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
+ if (socketListener->startListener(600)) {
+ exit(1);
+ }
// Loop forever -- the reports run on this thread in a handler, and the
// binder calls remain responsive in their pool of one thread.
diff --git a/cmds/statsd/src/socket/StatsSocketListener.cpp b/cmds/statsd/src/socket/StatsSocketListener.cpp
index aed926d..92200f9 100755
--- a/cmds/statsd/src/socket/StatsSocketListener.cpp
+++ b/cmds/statsd/src/socket/StatsSocketListener.cpp
@@ -41,8 +41,8 @@
static const int kLogMsgHeaderSize = 28;
-StatsSocketListener::StatsSocketListener(const sp<LogListener>& listener)
- : SocketListener(getLogSocket(), false /*start listen*/), mListener(listener) {
+StatsSocketListener::StatsSocketListener(std::shared_ptr<LogEventQueue> queue)
+ : SocketListener(getLogSocket(), false /*start listen*/), mQueue(queue) {
}
StatsSocketListener::~StatsSocketListener() {
@@ -134,10 +134,11 @@
msg.entry.uid = cred->uid;
memcpy(msg.buf + kLogMsgHeaderSize, ptr, n + 1);
- LogEvent event(msg);
- // Call the listener
- mListener->OnLogEvent(&event);
+ int64_t oldestTimestamp;
+ if (!mQueue->push(std::make_unique<LogEvent>(msg), &oldestTimestamp)) {
+ StatsdStats::getInstance().noteEventQueueOverflow(oldestTimestamp);
+ }
return true;
}
diff --git a/cmds/statsd/src/socket/StatsSocketListener.h b/cmds/statsd/src/socket/StatsSocketListener.h
index b8185d2..2167a56 100644
--- a/cmds/statsd/src/socket/StatsSocketListener.h
+++ b/cmds/statsd/src/socket/StatsSocketListener.h
@@ -17,7 +17,7 @@
#include <sysutils/SocketListener.h>
#include <utils/RefBase.h>
-#include "logd/LogListener.h"
+#include "logd/LogEventQueue.h"
// DEFAULT_OVERFLOWUID is defined in linux/highuid.h, which is not part of
// the uapi headers for userspace to use. This value is filled in on the
@@ -35,7 +35,7 @@
class StatsSocketListener : public SocketListener, public virtual android::RefBase {
public:
- explicit StatsSocketListener(const sp<LogListener>& listener);
+ explicit StatsSocketListener(std::shared_ptr<LogEventQueue> queue);
virtual ~StatsSocketListener();
@@ -47,7 +47,7 @@
/**
* Who is going to get the events when they're read.
*/
- sp<LogListener> mListener;
+ std::shared_ptr<LogEventQueue> mQueue;
};
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 967c3525..1dfc433 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -460,6 +460,14 @@
optional int32 pid = 6;
}
repeated LogLossStats detected_log_loss = 16;
+
+ message EventQueueOverflow {
+ optional int32 count = 1;
+ optional int64 max_queue_history_ns = 2;
+ optional int64 min_queue_history_ns = 3;
+ }
+
+ optional EventQueueOverflow queue_overflow = 18;
}
message AlertTriggerDetails {
diff --git a/cmds/statsd/tests/StatsService_test.cpp b/cmds/statsd/tests/StatsService_test.cpp
index 560fb9f..7c00531 100644
--- a/cmds/statsd/tests/StatsService_test.cpp
+++ b/cmds/statsd/tests/StatsService_test.cpp
@@ -33,7 +33,7 @@
#ifdef __ANDROID__
TEST(StatsServiceTest, TestAddConfig_simple) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
StatsdConfig config;
config.set_id(12345);
string serialized = config.SerializeAsString();
@@ -43,7 +43,7 @@
}
TEST(StatsServiceTest, TestAddConfig_empty) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
string serialized = "";
EXPECT_TRUE(
@@ -51,7 +51,7 @@
}
TEST(StatsServiceTest, TestAddConfig_invalid) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
string serialized = "Invalid config!";
EXPECT_FALSE(
@@ -69,7 +69,7 @@
int32_t uid;
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
service.mEngBuild = true;
// "-1"
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 3dff7f5..309d251 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -111,7 +111,7 @@
}
TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
SendConfig(service, MakeConfig());
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
@@ -126,7 +126,7 @@
}
TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
SendConfig(service, MakeConfig());
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
@@ -146,7 +146,7 @@
}
TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
SendConfig(service, MakeConfig());
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
@@ -171,7 +171,7 @@
}
TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
SendConfig(service, MakeConfig());
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
@@ -195,7 +195,7 @@
}
TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
SendConfig(service, MakeValueMetricConfig(0));
@@ -213,7 +213,7 @@
}
TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
@@ -237,7 +237,7 @@
}
TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
SendConfig(service, MakeGaugeMetricConfig(0));
@@ -255,7 +255,7 @@
}
TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
- StatsService service(nullptr);
+ StatsService service(nullptr, nullptr);
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
diff --git a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
new file mode 100644
index 0000000..f27d129
--- /dev/null
+++ b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
@@ -0,0 +1,100 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "logd/LogEventQueue.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+#include <stdio.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using namespace android;
+using namespace testing;
+
+using std::unique_ptr;
+
+#ifdef __ANDROID__
+TEST(LogEventQueue_test, TestGoodConsumer) {
+ LogEventQueue queue(50);
+ int64_t timeBaseNs = 100;
+ std::thread writer([&queue, timeBaseNs] {
+ for (int i = 0; i < 100; i++) {
+ int64_t oldestEventNs;
+ bool success = queue.push(std::make_unique<LogEvent>(10, timeBaseNs + i * 1000),
+ &oldestEventNs);
+ EXPECT_TRUE(success);
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+ });
+
+ std::thread reader([&queue, timeBaseNs] {
+ for (int i = 0; i < 100; i++) {
+ auto event = queue.waitPop();
+ EXPECT_TRUE(event != nullptr);
+ // All events are in right order.
+ EXPECT_EQ(timeBaseNs + i * 1000, event->GetElapsedTimestampNs());
+ }
+ });
+
+ reader.join();
+ writer.join();
+}
+
+TEST(LogEventQueue_test, TestSlowConsumer) {
+ LogEventQueue queue(50);
+ int64_t timeBaseNs = 100;
+ std::thread writer([&queue, timeBaseNs] {
+ int failure_count = 0;
+ int64_t oldestEventNs;
+ for (int i = 0; i < 100; i++) {
+ bool success = queue.push(std::make_unique<LogEvent>(10, timeBaseNs + i * 1000),
+ &oldestEventNs);
+ if (!success) failure_count++;
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+
+ // There is some remote chance that reader thread not get chance to run before writer thread
+ // ends. That's why the following comparison is not "==".
+ // There will be at least 45 events lost due to overflow.
+ EXPECT_TRUE(failure_count >= 45);
+ // The oldest event must be at least the 6th event.
+ EXPECT_TRUE(oldestEventNs <= (100 + 5 * 1000));
+ });
+
+ std::thread reader([&queue, timeBaseNs] {
+ // The consumer quickly processed 5 events, then it got stuck (not reading anymore).
+ for (int i = 0; i < 5; i++) {
+ auto event = queue.waitPop();
+ EXPECT_TRUE(event != nullptr);
+ // All events are in right order.
+ EXPECT_EQ(timeBaseNs + i * 1000, event->GetElapsedTimestampNs());
+ }
+ });
+
+ reader.join();
+ writer.join();
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 023371d..80b6349 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4037,7 +4037,7 @@
* continues running even if the process is killed and restarted. To remove the watch,
* use {@link #clearWatchHeapLimit()}.
*
- * <p>This API only work if the calling process has been marked as
+ * <p>This API only works if the calling process has been marked as
* {@link ApplicationInfo#FLAG_DEBUGGABLE} or this is running on a debuggable
* (userdebug or eng) build.</p>
*
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 08239a1..2441672 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2100,6 +2100,16 @@
public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
int flags, int userId) {
final boolean differentUser = (UserHandle.myUserId() != userId);
+ ApplicationInfo ai;
+ try {
+ ai = getPackageManager().getApplicationInfo(packageName,
+ PackageManager.GET_SHARED_LIBRARY_FILES
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+ (userId < 0) ? UserHandle.myUserId() : userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
if (differentUser) {
@@ -2112,11 +2122,7 @@
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
- //Slog.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo);
- //if (packageInfo != null) Slog.i(TAG, "isUptoDate " + packageInfo.mResDir
- // + ": " + packageInfo.mResources.getAssets().isUpToDate());
- if (packageInfo != null && (packageInfo.mResources == null
- || packageInfo.mResources.getAssets().isUpToDate())) {
+ if (ai != null && packageInfo != null && isLoadedApkUpToDate(packageInfo, ai)) {
if (packageInfo.isSecurityViolation()
&& (flags&Context.CONTEXT_IGNORE_SECURITY) == 0) {
throw new SecurityException(
@@ -2129,16 +2135,6 @@
}
}
- ApplicationInfo ai = null;
- try {
- ai = getPackageManager().getApplicationInfo(packageName,
- PackageManager.GET_SHARED_LIBRARY_FILES
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- (userId < 0) ? UserHandle.myUserId() : userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
if (ai != null) {
return getPackageInfo(ai, compatInfo, flags);
}
@@ -2209,37 +2205,59 @@
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
- if (packageInfo == null || (packageInfo.mResources != null
- && !packageInfo.mResources.getAssets().isUpToDate())) {
- if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package "
+
+ boolean isUpToDate = packageInfo != null && isLoadedApkUpToDate(packageInfo, aInfo);
+
+ if (isUpToDate) {
+ return packageInfo;
+ }
+
+ if (localLOGV) {
+ Slog.v(TAG, (includeCode ? "Loading code package "
: "Loading resource-only package ") + aInfo.packageName
+ " (in " + (mBoundApplication != null
- ? mBoundApplication.processName : null)
+ ? mBoundApplication.processName : null)
+ ")");
- packageInfo =
- new LoadedApk(this, aInfo, compatInfo, baseLoader,
- securityViolation, includeCode &&
- (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
-
- if (mSystemThread && "android".equals(aInfo.packageName)) {
- packageInfo.installSystemApplicationInfo(aInfo,
- getSystemContext().mPackageInfo.getClassLoader());
- }
-
- if (differentUser) {
- // Caching not supported across users
- } else if (includeCode) {
- mPackages.put(aInfo.packageName,
- new WeakReference<LoadedApk>(packageInfo));
- } else {
- mResourcePackages.put(aInfo.packageName,
- new WeakReference<LoadedApk>(packageInfo));
- }
}
+
+ packageInfo =
+ new LoadedApk(this, aInfo, compatInfo, baseLoader,
+ securityViolation, includeCode
+ && (aInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
+
+ if (mSystemThread && "android".equals(aInfo.packageName)) {
+ packageInfo.installSystemApplicationInfo(aInfo,
+ getSystemContext().mPackageInfo.getClassLoader());
+ }
+
+ if (differentUser) {
+ // Caching not supported across users
+ } else if (includeCode) {
+ mPackages.put(aInfo.packageName,
+ new WeakReference<LoadedApk>(packageInfo));
+ } else {
+ mResourcePackages.put(aInfo.packageName,
+ new WeakReference<LoadedApk>(packageInfo));
+ }
+
return packageInfo;
}
}
+ /**
+ * Compares overlay/resource directories for a LoadedApk to determine if it's up to date
+ * with the given ApplicationInfo.
+ */
+ private boolean isLoadedApkUpToDate(LoadedApk loadedApk, ApplicationInfo appInfo) {
+ Resources packageResources = loadedApk.mResources;
+ String[] overlayDirs = ArrayUtils.defeatNullable(loadedApk.getOverlayDirs());
+ String[] resourceDirs = ArrayUtils.defeatNullable(appInfo.resourceDirs);
+
+ return (packageResources == null || packageResources.getAssets().isUpToDate())
+ && overlayDirs.length == resourceDirs.length
+ && ArrayUtils.containsAll(overlayDirs, resourceDirs);
+ }
+
@UnsupportedAppUsage
ActivityThread() {
mResourcesManager = ResourcesManager.getInstance();
@@ -5434,19 +5452,25 @@
ref = mResourcePackages.get(ai.packageName);
resApk = ref != null ? ref.get() : null;
}
+
+ final String[] oldResDirs = new String[2];
+
if (apk != null) {
+ oldResDirs[0] = apk.getResDir();
final ArrayList<String> oldPaths = new ArrayList<>();
LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
apk.updateApplicationInfo(ai, oldPaths);
}
if (resApk != null) {
+ oldResDirs[1] = resApk.getResDir();
final ArrayList<String> oldPaths = new ArrayList<>();
LoadedApk.makePaths(this, resApk.getApplicationInfo(), oldPaths);
resApk.updateApplicationInfo(ai, oldPaths);
}
+
synchronized (mResourcesManager) {
// Update all affected Resources objects to use new ResourcesImpl
- mResourcesManager.applyNewResourceDirsLocked(ai.sourceDir, ai.resourceDirs);
+ mResourcesManager.applyNewResourceDirsLocked(ai, oldResDirs);
}
ApplicationPackageManager.configurationChanged();
@@ -5699,9 +5723,17 @@
}
}
}
+
+ final String[] oldResDirs = { pkgInfo.getResDir() };
+
final ArrayList<String> oldPaths = new ArrayList<>();
LoadedApk.makePaths(this, pkgInfo.getApplicationInfo(), oldPaths);
pkgInfo.updateApplicationInfo(aInfo, oldPaths);
+
+ synchronized (mResourcesManager) {
+ // Update affected Resources objects to use new ResourcesImpl
+ mResourcesManager.applyNewResourceDirsLocked(aInfo, oldResDirs);
+ }
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 2ef0856..8ec5e3a 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -27,6 +27,7 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Insets;
+import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.input.InputManager;
@@ -46,6 +47,7 @@
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewParent;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -81,6 +83,9 @@
// Temp container to store view coordinates in window.
private final int[] mLocationInWindow = new int[2];
+ // The latest tap exclude region that we've sent to WM.
+ private final Region mTapExcludeRegion = new Region();
+
private TaskStackListener mTaskStackListener;
private final CloseGuard mGuard = CloseGuard.get();
@@ -279,11 +284,11 @@
}
/**
- * Triggers an update of {@link ActivityView}'s location in window to properly set touch exclude
+ * Triggers an update of {@link ActivityView}'s location in window to properly set tap exclude
* regions and avoid focus switches by touches on this view.
*/
public void onLocationChanged() {
- updateLocation();
+ updateTapExcludeRegion();
}
@Override
@@ -291,15 +296,38 @@
mSurfaceView.layout(0 /* left */, 0 /* top */, r - l /* right */, b - t /* bottom */);
}
- /** Send current location and size to the WM to set tap exclude region for this view. */
- private void updateLocation() {
+ @Override
+ public boolean gatherTransparentRegion(Region region) {
+ // The tap exclude region may be affected by any view on top of it, so we detect the
+ // possible change by monitoring this function.
+ updateTapExcludeRegion();
+ return super.gatherTransparentRegion(region);
+ }
+
+ /** Compute and send current tap exclude region to WM for this view. */
+ private void updateTapExcludeRegion() {
if (!isAttachedToWindow()) {
return;
}
+ if (!canReceivePointerEvents()) {
+ cleanTapExcludeRegion();
+ return;
+ }
try {
getLocationInWindow(mLocationInWindow);
+ final int x = mLocationInWindow[0];
+ final int y = mLocationInWindow[1];
+ mTapExcludeRegion.set(x, y, x + getWidth(), y + getHeight());
+
+ // There might be views on top of us. We need to subtract those areas from the tap
+ // exclude region.
+ final ViewParent parent = getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).subtractObscuredTouchableRegion(mTapExcludeRegion, this);
+ }
+
WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
- mLocationInWindow[0], mLocationInWindow[1], getWidth(), getHeight());
+ mTapExcludeRegion);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
@@ -322,7 +350,7 @@
mVirtualDisplay.setDisplayState(true);
}
- updateLocation();
+ updateTapExcludeRegion();
}
@Override
@@ -330,7 +358,7 @@
if (mVirtualDisplay != null) {
mVirtualDisplay.resize(width, height, getBaseDisplayDensity());
}
- updateLocation();
+ updateTapExcludeRegion();
}
@Override
@@ -460,13 +488,14 @@
/** Report to server that tap exclude region on hosting display should be cleared. */
private void cleanTapExcludeRegion() {
- if (!isAttachedToWindow()) {
+ if (!isAttachedToWindow() || mTapExcludeRegion.isEmpty()) {
return;
}
- // Update tap exclude region with an empty rect to clean the state on server.
+ // Update tap exclude region with a null region to clean the state on server.
try {
WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
- 0 /* left */, 0 /* top */, 0 /* width */, 0 /* height */);
+ null /* region */);
+ mTapExcludeRegion.setEmpty();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 404e520..a906790 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3049,6 +3049,15 @@
}
@Override
+ public String getAttentionServicePackageName() {
+ try {
+ return mPM.getAttentionServicePackageName();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
public String getWellbeingPackageName() {
try {
return mPM.getWellbeingPackageName();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 11000df..41a4fba 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2122,8 +2122,7 @@
}
private static Resources createResources(IBinder activityToken, LoadedApk pi, String splitName,
- int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo,
- String[] overlayDirs) {
+ int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo) {
final String[] splitResDirs;
final ClassLoader classLoader;
try {
@@ -2135,7 +2134,7 @@
return ResourcesManager.getInstance().getResources(activityToken,
pi.getResDir(),
splitResDirs,
- overlayDirs,
+ pi.getOverlayDirs(),
pi.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfig,
@@ -2153,11 +2152,9 @@
new UserHandle(UserHandle.getUserId(application.uid)), flags, null, null);
final int displayId = getDisplayId();
- // overlayDirs is retrieved directly from ApplicationInfo since ActivityThread may have
- // a LoadedApk containing Resources with stale overlays for a remote application.
- final String[] overlayDirs = application.resourceDirs;
+
c.setResources(createResources(mActivityToken, pi, null, displayId, null,
- getDisplayAdjustments(displayId).getCompatibilityInfo(), overlayDirs));
+ getDisplayAdjustments(displayId).getCompatibilityInfo()));
if (c.mResources != null) {
return c;
}
@@ -2192,7 +2189,7 @@
final int displayId = getDisplayId();
c.setResources(createResources(mActivityToken, pi, null, displayId, null,
- getDisplayAdjustments(displayId).getCompatibilityInfo(), pi.getOverlayDirs()));
+ getDisplayAdjustments(displayId).getCompatibilityInfo()));
if (c.mResources != null) {
return c;
}
@@ -2242,8 +2239,7 @@
final int displayId = getDisplayId();
context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
- overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(),
- mPackageInfo.getOverlayDirs()));
+ overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo()));
return context;
}
@@ -2258,8 +2254,7 @@
final int displayId = display.getDisplayId();
context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
- null, getDisplayAdjustments(displayId).getCompatibilityInfo(),
- mPackageInfo.getOverlayDirs()));
+ null, getDisplayAdjustments(displayId).getCompatibilityInfo()));
context.mDisplay = display;
return context;
}
@@ -2441,7 +2436,7 @@
ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null,
null, null, 0, null, null);
context.setResources(createResources(null, packageInfo, null, displayId, null,
- packageInfo.getCompatibilityInfo(), packageInfo.getOverlayDirs()));
+ packageInfo.getCompatibilityInfo()));
context.updateDisplay(displayId);
return context;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5549d6b..11fa343 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -617,6 +617,13 @@
*/
public static final int FLAG_CAN_COLORIZE = 0x00000800;
+ /**
+ * Bit to be bitswised-ored into the {@link #flags} field that should be
+ * set if this notification can be shown as a bubble.
+ * @hide
+ */
+ public static final int FLAG_BUBBLE = 0x00001000;
+
public int flags;
/** @hide */
@@ -6243,6 +6250,15 @@
return false;
}
+ /**
+ * @return true if this is a notification that can show as a bubble.
+ *
+ * @hide
+ */
+ public boolean isBubbleNotification() {
+ return (flags & Notification.FLAG_BUBBLE) != 0;
+ }
+
private boolean hasLargeIcon() {
return mLargeIcon != null || largeIcon != null;
}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 5cdf85a..69ec831 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -170,6 +170,7 @@
private boolean mBlockableSystem = false;
private boolean mAllowBubbles = DEFAULT_ALLOW_BUBBLE;
private boolean mImportanceLockedByOEM;
+ private boolean mImportanceLockedDefaultApp;
/**
* Creates a notification channel.
@@ -656,11 +657,27 @@
* @hide
*/
@TestApi
+ public void setImportanceLockedByCriticalDeviceFunction(boolean locked) {
+ mImportanceLockedDefaultApp = locked;
+ }
+
+ /**
+ * @hide
+ */
+ @TestApi
public boolean isImportanceLockedByOEM() {
return mImportanceLockedByOEM;
}
/**
+ * @hide
+ */
+ @TestApi
+ public boolean isImportanceLockedByCriticalDeviceFunction() {
+ return mImportanceLockedDefaultApp;
+ }
+
+ /**
* Returns whether the user has chosen the importance of this channel, either to affirm the
* initial selection from the app, or changed it to be higher or lower.
* @see #getImportance()
@@ -834,6 +851,9 @@
out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(canBubble()));
}
+ // mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of
+ // truth and so aren't written to this xml file
+
out.endTag(null, TAG_CHANNEL);
}
@@ -942,7 +962,8 @@
return sb.toString();
}
- public static final @android.annotation.NonNull Creator<NotificationChannel> CREATOR = new Creator<NotificationChannel>() {
+ public static final @android.annotation.NonNull Creator<NotificationChannel> CREATOR =
+ new Creator<NotificationChannel>() {
@Override
public NotificationChannel createFromParcel(Parcel in) {
return new NotificationChannel(in);
@@ -983,7 +1004,8 @@
&& Arrays.equals(mVibration, that.mVibration)
&& Objects.equals(getGroup(), that.getGroup())
&& Objects.equals(getAudioAttributes(), that.getAudioAttributes())
- && mImportanceLockedByOEM == that.mImportanceLockedByOEM;
+ && mImportanceLockedByOEM == that.mImportanceLockedByOEM
+ && mImportanceLockedDefaultApp == that.mImportanceLockedDefaultApp;
}
@Override
@@ -993,7 +1015,7 @@
getUserLockedFields(),
isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
- mImportanceLockedByOEM);
+ mImportanceLockedByOEM, mImportanceLockedDefaultApp);
result = 31 * result + Arrays.hashCode(mVibration);
return result;
}
@@ -1022,6 +1044,7 @@
+ ", mBlockableSystem=" + mBlockableSystem
+ ", mAllowBubbles=" + mAllowBubbles
+ ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ + ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp
+ '}';
pw.println(prefix + output);
}
@@ -1049,6 +1072,7 @@
+ ", mBlockableSystem=" + mBlockableSystem
+ ", mAllowBubbles=" + mAllowBubbles
+ ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ + ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp
+ '}';
}
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 35658fb..b93aaa2 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.CompatResources;
@@ -32,6 +33,7 @@
import android.content.res.ResourcesKey;
import android.hardware.display.DisplayManagerGlobal;
import android.os.IBinder;
+import android.os.Process;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
@@ -1136,27 +1138,46 @@
}
// TODO(adamlesinski): Make this accept more than just overlay directories.
- final void applyNewResourceDirsLocked(@NonNull final String baseCodePath,
- @Nullable final String[] newResourceDirs) {
+ final void applyNewResourceDirsLocked(@NonNull final ApplicationInfo appInfo,
+ @Nullable final String[] oldPaths) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#applyNewResourceDirsLocked");
+ String baseCodePath = appInfo.getBaseCodePath();
+
+ final int myUid = Process.myUid();
+ String[] newSplitDirs = appInfo.uid == myUid
+ ? appInfo.splitSourceDirs
+ : appInfo.splitPublicSourceDirs;
+
+ // ApplicationInfo is mutable, so clone the arrays to prevent outside modification
+ String[] copiedSplitDirs = ArrayUtils.cloneOrNull(newSplitDirs);
+ String[] copiedResourceDirs = ArrayUtils.cloneOrNull(appInfo.resourceDirs);
+
final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>();
final int implCount = mResourceImpls.size();
for (int i = 0; i < implCount; i++) {
final ResourcesKey key = mResourceImpls.keyAt(i);
final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
- if (impl != null && (key.mResDir == null || key.mResDir.equals(baseCodePath))) {
+
+ if (impl == null) {
+ continue;
+ }
+
+ if (key.mResDir == null
+ || key.mResDir.equals(baseCodePath)
+ || ArrayUtils.contains(oldPaths, key.mResDir)) {
updatedResourceKeys.put(impl, new ResourcesKey(
- key.mResDir,
- key.mSplitResDirs,
- newResourceDirs,
+ baseCodePath,
+ copiedSplitDirs,
+ copiedResourceDirs,
key.mLibDirs,
key.mDisplayId,
key.mOverrideConfiguration,
- key.mCompatInfo));
+ key.mCompatInfo
+ ));
}
}
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
index 1727d34..76c4fb8 100644
--- a/core/java/android/content/ContentCaptureOptions.java
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -136,13 +136,18 @@
@Override
public String toString() {
if (lite) {
- return "ContentCaptureOptions [(lite) loggingLevel=" + loggingLevel + "]";
+ return "ContentCaptureOptions [loggingLevel=" + loggingLevel + " (lite)]";
}
- return "ContentCaptureOptions [loggingLevel=" + loggingLevel + ", maxBufferSize="
- + maxBufferSize + ", idleFlushingFrequencyMs=" + idleFlushingFrequencyMs
- + ", textChangeFlushingFrequencyMs=" + textChangeFlushingFrequencyMs
- + ", logHistorySize=" + logHistorySize + ", whitelistedComponents="
- + whitelistedComponents + "]";
+ final StringBuilder string = new StringBuilder("ContentCaptureOptions [");
+ string.append("loggingLevel=").append(loggingLevel)
+ .append(", maxBufferSize=").append(maxBufferSize)
+ .append(", idleFlushingFrequencyMs=").append(idleFlushingFrequencyMs)
+ .append(", textChangeFlushingFrequencyMs=").append(textChangeFlushingFrequencyMs)
+ .append(", logHistorySize=").append(logHistorySize);
+ if (whitelistedComponents != null) {
+ string.append(", whitelisted=").append(whitelistedComponents);
+ }
+ return string.append(']').toString();
}
/** @hide */
diff --git a/core/java/android/content/LocusId.java b/core/java/android/content/LocusId.java
index c67ff7c..283cea0 100644
--- a/core/java/android/content/LocusId.java
+++ b/core/java/android/content/LocusId.java
@@ -18,19 +18,50 @@
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.view.contentcapture.ContentCaptureManager;
import com.android.internal.util.Preconditions;
import java.io.PrintWriter;
/**
- * Identifier for an unique state in the application.
+ * An identifier for an unique state (locus) in the application. Should be stable across reboots and
+ * backup / restore.
*
- * <p>Should be stable across reboots and backup / restore.
+ * <p>Locus is a new concept introduced on
+ * {@link android.os.Build.VERSION_CODES#Q Android Q} and it lets the intelligence service provided
+ * by the Android System to correlate state between different subsystems such as content capture,
+ * shortcuts, and notifications.
*
- * <p>For example, a chat app could use the context to resume a conversation between 2 users.
+ * <p>For example, if your app provides an activiy representing a chat between 2 users
+ * (say {@code A} and {@code B}, this chat state could be represented by:
+ *
+ * <pre><code>
+ * LocusId chatId = new LocusId("Chat_A_B");
+ * </code></pre>
+ *
+ * <p>And then you should use that {@code chatId} by:
+ *
+ * <ul>
+ * <li>Setting it in the chat notification (through
+ * {@link android.app.Notification.Builder#setLocusId(LocusId)
+ * Notification.Builder.setLocusId(chatId)}).
+ * <li>Setting it into the {@link android.content.pm.ShortcutInfo} (through
+ * {@link android.content.pm.ShortcutInfo.Builder#setLocusId(LocusId)
+ * ShortcutInfo.Builder.setLocusId(chatId)}), if you provide a launcher shortcut for that chat
+ * conversation.
+ * <li>Associating it with the {@link android.view.contentcapture.ContentCaptureContext} of the
+ * root view of the chat conversation activity (through
+ * {@link android.view.View#getContentCaptureSession()}, then
+ * {@link android.view.contentcapture.ContentCaptureContext.Builder
+ * new ContentCaptureContext.Builder(chatId).build()} and
+ * {@link android.view.contentcapture.ContentCaptureSession#setContentCaptureContext(
+ * android.view.contentcapture.ContentCaptureContext)} - see {@link ContentCaptureManager}
+ * for more info about content capture).
+ * <li>Configuring your app to launch the chat conversation through the
+ * {@link Intent#ACTION_VIEW_LOCUS} intent.
+ * </ul>
*/
-// TODO(b/123577059): make sure this is well documented and understandable
public final class LocusId implements Parcelable {
private final String mId;
@@ -45,7 +76,7 @@
}
/**
- * Gets the {@code id} associated with the locus.
+ * Gets the canonical {@code id} associated with the locus.
*/
@NonNull
public String getId() {
@@ -100,7 +131,7 @@
parcel.writeString(mId);
}
- public static final @android.annotation.NonNull Parcelable.Creator<LocusId> CREATOR =
+ public static final @NonNull Parcelable.Creator<LocusId> CREATOR =
new Parcelable.Creator<LocusId>() {
@NonNull
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index aabe59d..b8c6d87 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -44,7 +44,7 @@
STATE_DISABLED,
STATE_ENABLED,
STATE_ENABLED_STATIC,
- STATE_TARGET_UPGRADING,
+ // @Deprecated STATE_TARGET_UPGRADING,
STATE_OVERLAY_UPGRADING,
})
/** @hide */
@@ -96,7 +96,14 @@
* The target package is currently being upgraded; the state will change
* once the package installation has finished.
* @hide
+ *
+ * @deprecated No longer used. Caused invalid transitions from enabled -> upgrading -> enabled,
+ * where an update is propagated when nothing has changed. Can occur during --dont-kill
+ * installs when code and resources are hot swapped and the Activity should not be relaunched.
+ * In all other cases, the process and therefore Activity is killed, so the state loop is
+ * irrelevant.
*/
+ @Deprecated
public static final int STATE_TARGET_UPGRADING = 4;
/**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 068a93a..5328dda 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -678,6 +678,14 @@
*/
public static final int PRIVATE_FLAG_IS_RESOURCE_OVERLAY = 1 << 28;
+ /**
+ * Value for {@link #privateFlags}: If {@code true} this app allows
+ * shared/external storage media to be a sandboxed view that only contains
+ * files owned by the app.
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX = 1 << 29;
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
@@ -707,7 +715,8 @@
PRIVATE_FLAG_VIRTUAL_PRELOAD,
PRIVATE_FLAG_HAS_FRAGILE_USER_DATA,
PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE,
- PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE
+ PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE,
+ PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoPrivateFlags {}
@@ -1822,6 +1831,16 @@
return (privateFlags & PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE) != 0;
}
+ /**
+ * If {@code true} this app allows shared/external storage media to be a
+ * sandboxed view that only contains files owned by the app.
+ *
+ * @hide
+ */
+ public boolean isExternalStorageSandboxAllowed() {
+ return (privateFlags & PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX) != 0;
+ }
+
private boolean isAllowedToUseHiddenApis() {
if (isSignedWithPlatformKey()) {
return true;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c798270..fb22187 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -740,6 +740,8 @@
String getSystemTextClassifierPackageName();
+ String getAttentionServicePackageName();
+
String getWellbeingPackageName();
String getAppPredictionServicePackageName();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 1e6cea3..5d6867e 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1211,6 +1211,9 @@
* Adds a session ID to the set of sessions that will be committed atomically
* when this session is committed.
*
+ * <p>If the parent is staged or has rollback enabled, all children must have
+ * the same properties.
+ *
* @param sessionId the session ID to add to this multi-package session.
*/
public void addChildSessionId(int sessionId) {
@@ -1480,6 +1483,9 @@
/**
* Request that rollbacks be enabled or disabled for the given upgrade.
*
+ * <p>If the parent session is staged or has rollback enabled, all children sessions
+ * must have the same properties.
+ *
* @param enable set to {@code true} to enable, {@code false} to disable
* @hide
*/
@@ -1607,6 +1613,9 @@
* multi-package. In that case, if any of the children sessions fail to install at reboot,
* all the other children sessions are aborted as well.
*
+ * <p>If the parent session is staged or has rollback enabled, all children sessions
+ * must have the same properties.
+ *
* {@hide}
*/
@SystemApi @TestApi
@@ -1626,6 +1635,11 @@
installFlags |= PackageManager.INSTALL_APEX;
}
+ /** @hide */
+ public boolean getEnableRollback() {
+ return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0;
+ }
+
/** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b190b34..8f7df25 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1397,6 +1397,14 @@
*/
public static final int INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS = -119;
+ /**
+ * Installation failed return code: one of the child sessions does not match the parent session
+ * in respect to staged or rollback enabled parameters.
+ *
+ * @hide
+ */
+ public static final int INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY = -120;
+
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,
@@ -3214,7 +3222,8 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags)
+ public abstract PackageInfo getPackageInfo(@NonNull String packageName,
+ @PackageInfoFlags int flags)
throws NameNotFoundException;
/**
@@ -3239,7 +3248,7 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract PackageInfo getPackageInfo(VersionedPackage versionedPackage,
+ public abstract PackageInfo getPackageInfo(@NonNull VersionedPackage versionedPackage,
@PackageInfoFlags int flags) throws NameNotFoundException;
/**
@@ -3263,25 +3272,25 @@
*/
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
@UnsupportedAppUsage
- public abstract PackageInfo getPackageInfoAsUser(String packageName,
+ public abstract PackageInfo getPackageInfoAsUser(@NonNull String packageName,
@PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
/**
* Map from the current package names in use on the device to whatever
* the current canonical name of that package is.
- * @param names Array of current names to be mapped.
+ * @param packageNames Array of current names to be mapped.
* @return Returns an array of the same size as the original, containing
* the canonical name for each package.
*/
- public abstract String[] currentToCanonicalPackageNames(String[] names);
+ public abstract String[] currentToCanonicalPackageNames(@NonNull String[] packageNames);
/**
* Map from a packages canonical name to the current name in use on the device.
- * @param names Array of new names to be mapped.
+ * @param packageNames Array of new names to be mapped.
* @return Returns an array of the same size as the original, containing
* the current name for each package.
*/
- public abstract String[] canonicalToCurrentPackageNames(String[] names);
+ public abstract String[] canonicalToCurrentPackageNames(@NonNull String[] packageNames);
/**
* Returns a "good" intent to launch a front-door activity in a package.
@@ -3360,7 +3369,7 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract int[] getPackageGids(String packageName, @PackageInfoFlags int flags)
+ public abstract int[] getPackageGids(@NonNull String packageName, @PackageInfoFlags int flags)
throws NameNotFoundException;
/**
@@ -3375,7 +3384,7 @@
* @throws NameNotFoundException if a package with the given name can not be
* found on the system.
*/
- public abstract int getPackageUid(String packageName, @PackageInfoFlags int flags)
+ public abstract int getPackageUid(@NonNull String packageName, @PackageInfoFlags int flags)
throws NameNotFoundException;
/**
@@ -3393,7 +3402,7 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract int getPackageUidAsUser(String packageName, @UserIdInt int userId)
+ public abstract int getPackageUidAsUser(@NonNull String packageName, @UserIdInt int userId)
throws NameNotFoundException;
/**
@@ -3411,13 +3420,13 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract int getPackageUidAsUser(String packageName, @PackageInfoFlags int flags,
- @UserIdInt int userId) throws NameNotFoundException;
+ public abstract int getPackageUidAsUser(@NonNull String packageName,
+ @PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular permission.
*
- * @param name The fully qualified name (i.e. com.google.permission.LOGIN)
+ * @param permissionName The fully qualified name (i.e. com.google.permission.LOGIN)
* of the permission you are interested in.
* @param flags Additional option flags to modify the data returned.
* @return Returns a {@link PermissionInfo} containing information about the
@@ -3425,13 +3434,13 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract PermissionInfo getPermissionInfo(String name, @PermissionInfoFlags int flags)
- throws NameNotFoundException;
+ public abstract PermissionInfo getPermissionInfo(@NonNull String permissionName,
+ @PermissionInfoFlags int flags) throws NameNotFoundException;
/**
* Query for all of the permissions associated with a particular group.
*
- * @param group The fully qualified name (i.e. com.google.permission.LOGIN)
+ * @param permissionGroup The fully qualified name (i.e. com.google.permission.LOGIN)
* of the permission group you are interested in. Use null to
* find all of the permissions not associated with a group.
* @param flags Additional option flags to modify the data returned.
@@ -3440,7 +3449,8 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract List<PermissionInfo> queryPermissionsByGroup(String group,
+ @NonNull
+ public abstract List<PermissionInfo> queryPermissionsByGroup(@NonNull String permissionGroup,
@PermissionInfoFlags int flags) throws NameNotFoundException;
/**
@@ -3465,7 +3475,7 @@
* Retrieve all of the information we know about a particular group of
* permissions.
*
- * @param name The fully qualified name (i.e.
+ * @param permissionName The fully qualified name (i.e.
* com.google.permission_group.APPS) of the permission you are
* interested in.
* @param flags Additional option flags to modify the data returned.
@@ -3474,7 +3484,8 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract PermissionGroupInfo getPermissionGroupInfo(String name,
+ @NonNull
+ public abstract PermissionGroupInfo getPermissionGroupInfo(@NonNull String permissionName,
@PermissionGroupInfoFlags int flags) throws NameNotFoundException;
/**
@@ -3484,6 +3495,7 @@
* @return Returns a list of {@link PermissionGroupInfo} containing
* information about all of the known permission groups.
*/
+ @NonNull
public abstract List<PermissionGroupInfo> getAllPermissionGroups(
@PermissionGroupInfoFlags int flags);
@@ -3504,12 +3516,14 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract ApplicationInfo getApplicationInfo(String packageName,
+ @NonNull
+ public abstract ApplicationInfo getApplicationInfo(@NonNull String packageName,
@ApplicationInfoFlags int flags) throws NameNotFoundException;
/** {@hide} */
+ @NonNull
@UnsupportedAppUsage
- public abstract ApplicationInfo getApplicationInfoAsUser(String packageName,
+ public abstract ApplicationInfo getApplicationInfoAsUser(@NonNull String packageName,
@ApplicationInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
/**
@@ -3552,7 +3566,8 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract ActivityInfo getActivityInfo(ComponentName component,
+ @NonNull
+ public abstract ActivityInfo getActivityInfo(@NonNull ComponentName component,
@ComponentInfoFlags int flags) throws NameNotFoundException;
/**
@@ -3568,7 +3583,8 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract ActivityInfo getReceiverInfo(ComponentName component,
+ @NonNull
+ public abstract ActivityInfo getReceiverInfo(@NonNull ComponentName component,
@ComponentInfoFlags int flags) throws NameNotFoundException;
/**
@@ -3583,7 +3599,8 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract ServiceInfo getServiceInfo(ComponentName component,
+ @NonNull
+ public abstract ServiceInfo getServiceInfo(@NonNull ComponentName component,
@ComponentInfoFlags int flags) throws NameNotFoundException;
/**
@@ -3599,7 +3616,8 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract ProviderInfo getProviderInfo(ComponentName component,
+ @NonNull
+ public abstract ProviderInfo getProviderInfo(@NonNull ComponentName component,
@ComponentInfoFlags int flags) throws NameNotFoundException;
/**
@@ -3612,7 +3630,8 @@
* @throws NameNotFoundException if a module with the given name cannot be
* found on the system.
*/
- public ModuleInfo getModuleInfo(String packageName, @ModuleInfoFlags int flags)
+ @NonNull
+ public ModuleInfo getModuleInfo(@NonNull String packageName, @ModuleInfoFlags int flags)
throws NameNotFoundException {
throw new UnsupportedOperationException(
"getModuleInfo not implemented in subclass");
@@ -3626,7 +3645,8 @@
* module, containing information about the module. In the unlikely case
* there are no installed modules, an empty list is returned.
*/
- public @NonNull List<ModuleInfo> getInstalledModules(@ModuleInfoFlags int flags) {
+ @NonNull
+ public List<ModuleInfo> getInstalledModules(@ModuleInfoFlags int flags) {
throw new UnsupportedOperationException(
"getInstalledModules not implemented in subclass");
}
@@ -3644,6 +3664,7 @@
* applications with data directory i.e. applications which had been
* deleted with {@code DONT_DELETE_DATA} flag set).
*/
+ @NonNull
public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);
/**
@@ -3661,8 +3682,9 @@
* applications with data directory i.e. applications which had been
* deleted with {@code DONT_DELETE_DATA} flag set).
*/
+ @NonNull
public abstract List<PackageInfo> getPackagesHoldingPermissions(
- String[] permissions, @PackageInfoFlags int flags);
+ @NonNull String[] permissions, @PackageInfoFlags int flags);
/**
* Return a List of all packages that are installed on the device, for a
@@ -3680,6 +3702,7 @@
* deleted with {@code DONT_DELETE_DATA} flag set).
* @hide
*/
+ @NonNull
@TestApi
@SystemApi
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@@ -3690,8 +3713,8 @@
* Check whether a particular package has been granted a particular
* permission.
*
- * @param permName The name of the permission you are checking for.
- * @param pkgName The name of the package you are checking against.
+ * @param permissionName The name of the permission you are checking for.
+ * @param packageName The name of the package you are checking against.
*
* @return If the package has the permission, PERMISSION_GRANTED is
* returned. If it does not have the permission, PERMISSION_DENIED
@@ -3701,7 +3724,9 @@
* @see #PERMISSION_DENIED
*/
@CheckResult
- public abstract @PermissionResult int checkPermission(String permName, String pkgName);
+ @PermissionResult
+ public abstract int checkPermission(@NonNull String permissionName,
+ @NonNull String packageName);
/**
* Checks whether a particular permissions has been revoked for a
@@ -3710,14 +3735,14 @@
* permissions, hence the only way for an app to get such a permission
* is by a policy change.
*
- * @param permName The name of the permission you are checking for.
- * @param pkgName The name of the package you are checking against.
+ * @param permissionName The name of the permission you are checking for.
+ * @param packageName The name of the package you are checking against.
*
* @return Whether the permission is restricted by policy.
*/
@CheckResult
- public abstract boolean isPermissionRevokedByPolicy(@NonNull String permName,
- @NonNull String pkgName);
+ public abstract boolean isPermissionRevokedByPolicy(@NonNull String permissionName,
+ @NonNull String packageName);
/**
* Gets the package name of the component controlling runtime permissions.
@@ -3726,6 +3751,7 @@
*
* @hide
*/
+ @NonNull
@TestApi
public abstract String getPermissionControllerPackageName();
@@ -3761,7 +3787,7 @@
*
* @see #removePermission(String)
*/
- public abstract boolean addPermission(PermissionInfo info);
+ public abstract boolean addPermission(@NonNull PermissionInfo info);
/**
* Like {@link #addPermission(PermissionInfo)} but asynchronously
@@ -3770,7 +3796,7 @@
* expense of no guarantee the added permission will be retained if
* the device is rebooted before it is written.
*/
- public abstract boolean addPermissionAsync(PermissionInfo info);
+ public abstract boolean addPermissionAsync(@NonNull PermissionInfo info);
/**
* Removes a permission that was previously added with
@@ -3778,14 +3804,14 @@
* -- you are only allowed to remove permissions that you are allowed
* to add.
*
- * @param name The name of the permission to remove.
+ * @param permissionName The name of the permission to remove.
*
* @throws SecurityException if you are not allowed to remove the
* given permission name.
*
* @see #addPermission(PermissionInfo)
*/
- public abstract void removePermission(String name);
+ public abstract void removePermission(@NonNull String permissionName);
/**
* Permission flags set when granting or revoking a permission.
@@ -3880,8 +3906,9 @@
android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
android.Manifest.permission.GET_RUNTIME_PERMISSIONS
})
- public abstract @PermissionFlags int getPermissionFlags(String permissionName,
- String packageName, @NonNull UserHandle user);
+ @PermissionFlags
+ public abstract int getPermissionFlags(@NonNull String permissionName,
+ @NonNull String packageName, @NonNull UserHandle user);
/**
* Updates the flags associated with a permission by replacing the flags in
@@ -3901,9 +3928,9 @@
android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
})
- public abstract void updatePermissionFlags(String permissionName,
- String packageName, @PermissionFlags int flagMask, @PermissionFlags int flagValues,
- @NonNull UserHandle user);
+ public abstract void updatePermissionFlags(@NonNull String permissionName,
+ @NonNull String packageName, @PermissionFlags int flagMask,
+ @PermissionFlags int flagValues, @NonNull UserHandle user);
/**
* Gets whether you should show UI with rationale for requesting a permission.
@@ -3911,13 +3938,13 @@
* which the permission is requested does not clearly communicate to the user
* what would be the benefit from grating this permission.
*
- * @param permission A permission your app wants to request.
+ * @param permissionName A permission your app wants to request.
* @return Whether you can show permission rationale UI.
*
* @hide
*/
@UnsupportedAppUsage
- public abstract boolean shouldShowRequestPermissionRationale(String permission);
+ public abstract boolean shouldShowRequestPermissionRationale(@NonNull String permissionName);
/**
* Returns an {@link android.content.Intent} suitable for passing to
@@ -3928,6 +3955,7 @@
*
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
if (ArrayUtils.isEmpty(permissions)) {
@@ -3946,8 +3974,8 @@
* with each other: they can share the same user-id, run instrumentation
* against each other, etc.
*
- * @param pkg1 First package name whose signature will be compared.
- * @param pkg2 Second package name whose signature will be compared.
+ * @param packageName1 First package name whose signature will be compared.
+ * @param packageName2 Second package name whose signature will be compared.
*
* @return Returns an integer indicating whether all signatures on the
* two packages match. The value is >= 0 ({@link #SIGNATURE_MATCH}) if
@@ -3957,7 +3985,9 @@
* @see #checkSignatures(int, int)
*/
@CheckResult
- public abstract @SignatureResult int checkSignatures(String pkg1, String pkg2);
+ @SignatureResult
+ public abstract int checkSignatures(@NonNull String packageName1,
+ @NonNull String packageName2);
/**
* Like {@link #checkSignatures(String, String)}, but takes UIDs of
@@ -4030,7 +4060,7 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract int getUidForSharedUser(String sharedUserName)
+ public abstract int getUidForSharedUser(@NonNull String sharedUserName)
throws NameNotFoundException;
/**
@@ -4049,6 +4079,7 @@
* applications with data directory i.e. applications which had been
* deleted with {@code DONT_DELETE_DATA} flag set).
*/
+ @NonNull
public abstract List<ApplicationInfo> getInstalledApplications(@ApplicationInfoFlags int flags);
/**
@@ -4071,6 +4102,7 @@
* deleted with {@code DONT_DELETE_DATA} flag set).
* @hide
*/
+ @NonNull
@TestApi
public abstract List<ApplicationInfo> getInstalledApplicationsAsUser(
@ApplicationInfoFlags int flags, @UserIdInt int userId);
@@ -4121,7 +4153,7 @@
* @see #getInstantAppCookieMaxBytes()
* @see #clearInstantAppCookie()
*/
- public abstract boolean isInstantApp(String packageName);
+ public abstract boolean isInstantApp(@NonNull String packageName);
/**
* Gets the maximum size in bytes of the cookie data an instant app
@@ -4208,6 +4240,7 @@
* available on the system, or null if none are installed.
*
*/
+ @Nullable
public abstract String[] getSystemSharedLibraryNames();
/**
@@ -4296,6 +4329,7 @@
* @return An array of FeatureInfo classes describing the features
* that are available on the system, or null if there are none(!!).
*/
+ @NonNull
public abstract FeatureInfo[] getSystemAvailableFeatures();
/**
@@ -4306,7 +4340,7 @@
*
* @return Returns true if the devices supports the feature, else false.
*/
- public abstract boolean hasSystemFeature(String name);
+ public abstract boolean hasSystemFeature(@NonNull String featureName);
/**
* Check whether the given feature name and version is one of the available
@@ -4317,7 +4351,7 @@
*
* @return Returns true if the devices supports the feature, else false.
*/
- public abstract boolean hasSystemFeature(String name, int version);
+ public abstract boolean hasSystemFeature(@NonNull String featureName, int version);
/**
* Determine the best action to perform for a given Intent. This is how
@@ -4345,7 +4379,9 @@
* found and there is no default set, returns a ResolveInfo object
* containing something else, such as the activity resolver.
*/
- public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);
+ @Nullable
+ public abstract ResolveInfo resolveActivity(@NonNull Intent intent,
+ @ResolveInfoFlags int flags);
/**
* Determine the best action to perform for a given Intent for a given user.
@@ -4375,9 +4411,10 @@
* containing something else, such as the activity resolver.
* @hide
*/
+ @Nullable
@UnsupportedAppUsage
- public abstract ResolveInfo resolveActivityAsUser(Intent intent, @ResolveInfoFlags int flags,
- @UserIdInt int userId);
+ public abstract ResolveInfo resolveActivityAsUser(@NonNull Intent intent,
+ @ResolveInfoFlags int flags, @UserIdInt int userId);
/**
* Retrieve all activities that can be performed for the given intent.
@@ -4394,7 +4431,8 @@
* {@link #resolveActivity}. If there are no matching activities, an
* empty list is returned.
*/
- public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
+ @Nullable
+ public abstract List<ResolveInfo> queryIntentActivities(@NonNull Intent intent,
@ResolveInfoFlags int flags);
/**
@@ -4414,8 +4452,9 @@
* empty list is returned.
* @hide
*/
+ @Nullable
@UnsupportedAppUsage
- public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
+ public abstract List<ResolveInfo> queryIntentActivitiesAsUser(@NonNull Intent intent,
@ResolveInfoFlags int flags, @UserIdInt int userId);
/**
@@ -4469,8 +4508,9 @@
* included by one of the <var>specifics</var> intents. If there are
* no matching activities, an empty list is returned.
*/
+ @NonNull
public abstract List<ResolveInfo> queryIntentActivityOptions(@Nullable ComponentName caller,
- @Nullable Intent[] specifics, Intent intent, @ResolveInfoFlags int flags);
+ @Nullable Intent[] specifics, @NonNull Intent intent, @ResolveInfoFlags int flags);
/**
* Retrieve all receivers that can handle a broadcast of the given intent.
@@ -4481,7 +4521,8 @@
* each matching receiver, ordered from best to worst. If there are
* no matching receivers, an empty list or null is returned.
*/
- public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
+ @NonNull
+ public abstract List<ResolveInfo> queryBroadcastReceivers(@NonNull Intent intent,
@ResolveInfoFlags int flags);
/**
@@ -4496,9 +4537,10 @@
* no matching receivers, an empty list or null is returned.
* @hide
*/
+ @NonNull
@SystemApi
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
- public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+ public List<ResolveInfo> queryBroadcastReceiversAsUser(@NonNull Intent intent,
@ResolveInfoFlags int flags, UserHandle userHandle) {
return queryBroadcastReceiversAsUser(intent, flags, userHandle.getIdentifier());
}
@@ -4506,15 +4548,17 @@
/**
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
- public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+ public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(@NonNull Intent intent,
@ResolveInfoFlags int flags, @UserIdInt int userId);
- /** {@hide} */
+ /** @deprecated @hide */
+ @NonNull
@Deprecated
@UnsupportedAppUsage
- public List<ResolveInfo> queryBroadcastReceivers(Intent intent,
+ public List<ResolveInfo> queryBroadcastReceivers(@NonNull Intent intent,
@ResolveInfoFlags int flags, @UserIdInt int userId) {
final String msg = "Shame on you for calling the hidden API "
+ "queryBroadcastReceivers(). Shame!";
@@ -4536,13 +4580,15 @@
* that was determined to be the best action. Returns null if no
* matching service was found.
*/
- public abstract ResolveInfo resolveService(Intent intent, @ResolveInfoFlags int flags);
+ @Nullable
+ public abstract ResolveInfo resolveService(@NonNull Intent intent, @ResolveInfoFlags int flags);
/**
* @hide
*/
- public abstract ResolveInfo resolveServiceAsUser(Intent intent, @ResolveInfoFlags int flags,
- @UserIdInt int userId);
+ @Nullable
+ public abstract ResolveInfo resolveServiceAsUser(@NonNull Intent intent,
+ @ResolveInfoFlags int flags, @UserIdInt int userId);
/**
* Retrieve all services that can match the given intent.
@@ -4555,7 +4601,8 @@
* {@link #resolveService}. If there are no matching services, an
* empty list or null is returned.
*/
- public abstract List<ResolveInfo> queryIntentServices(Intent intent,
+ @NonNull
+ public abstract List<ResolveInfo> queryIntentServices(@NonNull Intent intent,
@ResolveInfoFlags int flags);
/**
@@ -4571,8 +4618,9 @@
* empty list or null is returned.
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
- public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
+ public abstract List<ResolveInfo> queryIntentServicesAsUser(@NonNull Intent intent,
@ResolveInfoFlags int flags, @UserIdInt int userId);
/**
@@ -4608,9 +4656,10 @@
* no matching services, an empty list or null is returned.
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
- Intent intent, @ResolveInfoFlags int flags, @UserIdInt int userId);
+ @NonNull Intent intent, @ResolveInfoFlags int flags, @UserIdInt int userId);
/**
* Retrieve all providers that can match the given intent.
@@ -4642,7 +4691,8 @@
* each matching provider, ordered from best to worst. If there are
* no matching services, an empty list or null is returned.
*/
- public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent,
+ @NonNull
+ public abstract List<ResolveInfo> queryIntentContentProviders(@NonNull Intent intent,
@ResolveInfoFlags int flags);
/**
@@ -4659,21 +4709,23 @@
* @return A {@link ProviderInfo} object containing information about the
* provider. If a provider was not found, returns null.
*/
- public abstract ProviderInfo resolveContentProvider(String authority,
+ @Nullable
+ public abstract ProviderInfo resolveContentProvider(@NonNull String authority,
@ComponentInfoFlags int flags);
/**
* Find a single content provider by its base path name.
*
- * @param name The name of the provider to find.
+ * @param providerName The name of the provider to find.
* @param flags Additional option flags to modify the data returned.
* @param userId The user id.
* @return A {@link ProviderInfo} object containing information about the
* provider. If a provider was not found, returns null.
* @hide
*/
+ @Nullable
@UnsupportedAppUsage
- public abstract ProviderInfo resolveContentProviderAsUser(String name,
+ public abstract ProviderInfo resolveContentProviderAsUser(@NonNull String providerName,
@ComponentInfoFlags int flags, @UserIdInt int userId);
/**
@@ -4693,8 +4745,9 @@
* <var>processName</var> is null, all known content providers.
* <em>If there are no matching providers, null is returned.</em>
*/
+ @NonNull
public abstract List<ProviderInfo> queryContentProviders(
- String processName, int uid, @ComponentInfoFlags int flags);
+ @Nullable String processName, int uid, @ComponentInfoFlags int flags);
/**
* Same as {@link #queryContentProviders}, except when {@code metaDataKey} is not null,
@@ -4711,8 +4764,9 @@
*
* @hide
*/
- public List<ProviderInfo> queryContentProviders(
- String processName, int uid, @ComponentInfoFlags int flags, String metaDataKey) {
+ @NonNull
+ public List<ProviderInfo> queryContentProviders(@Nullable String processName,
+ int uid, @ComponentInfoFlags int flags, String metaDataKey) {
// Provide the default implementation for mocks.
return queryContentProviders(processName, uid, flags);
}
@@ -4730,7 +4784,8 @@
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
*/
- public abstract InstrumentationInfo getInstrumentationInfo(ComponentName className,
+ @NonNull
+ public abstract InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName className,
@InstrumentationInfoFlags int flags) throws NameNotFoundException;
/**
@@ -4745,7 +4800,8 @@
* entry for each matching instrumentation. If there are no
* instrumentation available, returns an empty list.
*/
- public abstract List<InstrumentationInfo> queryInstrumentation(String targetPackage,
+ @NonNull
+ public abstract List<InstrumentationInfo> queryInstrumentation(@NonNull String targetPackage,
@InstrumentationInfoFlags int flags);
/**
@@ -4765,8 +4821,9 @@
* @return Returns a Drawable holding the requested image. Returns null if
* an image could not be found for any reason.
*/
- public abstract Drawable getDrawable(String packageName, @DrawableRes int resid,
- ApplicationInfo appInfo);
+ @Nullable
+ public abstract Drawable getDrawable(@NonNull String packageName, @DrawableRes int resid,
+ @Nullable ApplicationInfo appInfo);
/**
* Retrieve the icon associated with an activity. Given the full name of
@@ -4783,7 +4840,8 @@
*
* @see #getActivityIcon(Intent)
*/
- public abstract Drawable getActivityIcon(ComponentName activityName)
+ @NonNull
+ public abstract Drawable getActivityIcon(@NonNull ComponentName activityName)
throws NameNotFoundException;
/**
@@ -4803,7 +4861,8 @@
*
* @see #getActivityIcon(ComponentName)
*/
- public abstract Drawable getActivityIcon(Intent intent)
+ @NonNull
+ public abstract Drawable getActivityIcon(@NonNull Intent intent)
throws NameNotFoundException;
/**
@@ -4819,7 +4878,8 @@
* activity could not be loaded.
* @see #getActivityBanner(Intent)
*/
- public abstract Drawable getActivityBanner(ComponentName activityName)
+ @Nullable
+ public abstract Drawable getActivityBanner(@NonNull ComponentName activityName)
throws NameNotFoundException;
/**
@@ -4837,7 +4897,8 @@
* matching the given intent could not be loaded.
* @see #getActivityBanner(ComponentName)
*/
- public abstract Drawable getActivityBanner(Intent intent)
+ @Nullable
+ public abstract Drawable getActivityBanner(@NonNull Intent intent)
throws NameNotFoundException;
/**
@@ -4846,6 +4907,7 @@
*
* @return Drawable Image of the icon.
*/
+ @NonNull
public abstract Drawable getDefaultActivityIcon();
/**
@@ -4859,7 +4921,8 @@
*
* @see #getApplicationIcon(String)
*/
- public abstract Drawable getApplicationIcon(ApplicationInfo info);
+ @NonNull
+ public abstract Drawable getApplicationIcon(@NonNull ApplicationInfo info);
/**
* Retrieve the icon associated with an application. Given the name of the
@@ -4877,7 +4940,8 @@
*
* @see #getApplicationIcon(ApplicationInfo)
*/
- public abstract Drawable getApplicationIcon(String packageName)
+ @NonNull
+ public abstract Drawable getApplicationIcon(@NonNull String packageName)
throws NameNotFoundException;
/**
@@ -4888,7 +4952,8 @@
* banner specified.
* @see #getApplicationBanner(String)
*/
- public abstract Drawable getApplicationBanner(ApplicationInfo info);
+ @Nullable
+ public abstract Drawable getApplicationBanner(@NonNull ApplicationInfo info);
/**
* Retrieve the banner associated with an application. Given the name of the
@@ -4904,7 +4969,8 @@
* application could not be loaded.
* @see #getApplicationBanner(ApplicationInfo)
*/
- public abstract Drawable getApplicationBanner(String packageName)
+ @Nullable
+ public abstract Drawable getApplicationBanner(@NonNull String packageName)
throws NameNotFoundException;
/**
@@ -4920,7 +4986,8 @@
* activity could not be loaded.
* @see #getActivityLogo(Intent)
*/
- public abstract Drawable getActivityLogo(ComponentName activityName)
+ @Nullable
+ public abstract Drawable getActivityLogo(@NonNull ComponentName activityName)
throws NameNotFoundException;
/**
@@ -4941,7 +5008,8 @@
*
* @see #getActivityLogo(ComponentName)
*/
- public abstract Drawable getActivityLogo(Intent intent)
+ @Nullable
+ public abstract Drawable getActivityLogo(@NonNull Intent intent)
throws NameNotFoundException;
/**
@@ -4955,7 +5023,8 @@
*
* @see #getApplicationLogo(String)
*/
- public abstract Drawable getApplicationLogo(ApplicationInfo info);
+ @Nullable
+ public abstract Drawable getApplicationLogo(@NonNull ApplicationInfo info);
/**
* Retrieve the logo associated with an application. Given the name of the
@@ -4974,7 +5043,8 @@
*
* @see #getApplicationLogo(ApplicationInfo)
*/
- public abstract Drawable getApplicationLogo(String packageName)
+ @Nullable
+ public abstract Drawable getApplicationLogo(@NonNull String packageName)
throws NameNotFoundException;
/**
@@ -4988,12 +5058,14 @@
* is performed in place and the original drawable is returned.
* </p>
*
- * @param icon The icon to badge.
+ * @param drawable The drawable to badge.
* @param user The target user.
* @return A drawable that combines the original icon and a badge as
* determined by the system.
*/
- public abstract Drawable getUserBadgedIcon(Drawable icon, UserHandle user);
+ @NonNull
+ public abstract Drawable getUserBadgedIcon(@NonNull Drawable drawable,
+ @NonNull UserHandle user);
/**
* If the target user is a managed profile of the calling user or the caller
@@ -5019,8 +5091,9 @@
* @return A drawable that combines the original drawable and a badge as
* determined by the system.
*/
- public abstract Drawable getUserBadgedDrawableForDensity(Drawable drawable,
- UserHandle user, Rect badgeLocation, int badgeDensity);
+ @NonNull
+ public abstract Drawable getUserBadgedDrawableForDensity(@NonNull Drawable drawable,
+ @NonNull UserHandle user, @Nullable Rect badgeLocation, int badgeDensity);
/**
* If the target user is a managed profile of the calling user or the caller
@@ -5034,8 +5107,9 @@
* @return the drawable or null if no drawable is required.
* @hide
*/
+ @Nullable
@UnsupportedAppUsage
- public abstract Drawable getUserBadgeForDensity(UserHandle user, int density);
+ public abstract Drawable getUserBadgeForDensity(@NonNull UserHandle user, int density);
/**
* If the target user is a managed profile of the calling user or the caller
@@ -5051,8 +5125,10 @@
* @return the drawable or null if no drawable is required.
* @hide
*/
+ @Nullable
@UnsupportedAppUsage
- public abstract Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density);
+ public abstract Drawable getUserBadgeForDensityNoBackground(@NonNull UserHandle user,
+ int density);
/**
* If the target user is a managed profile of the calling user or the caller
@@ -5065,7 +5141,9 @@
* @return A label that combines the original label and a badge as
* determined by the system.
*/
- public abstract CharSequence getUserBadgedLabel(CharSequence label, UserHandle user);
+ @NonNull
+ public abstract CharSequence getUserBadgedLabel(@NonNull CharSequence label,
+ @NonNull UserHandle user);
/**
* Retrieve text from a package. This is a low-level API used by
@@ -5084,8 +5162,9 @@
* @return Returns a CharSequence holding the requested text. Returns null
* if the text could not be found for any reason.
*/
- public abstract CharSequence getText(String packageName, @StringRes int resid,
- ApplicationInfo appInfo);
+ @Nullable
+ public abstract CharSequence getText(@NonNull String packageName, @StringRes int resid,
+ @Nullable ApplicationInfo appInfo);
/**
* Retrieve an XML file from a package. This is a low-level API used to
@@ -5103,8 +5182,9 @@
* data. Returns null if the xml resource could not be found for any
* reason.
*/
- public abstract XmlResourceParser getXml(String packageName, @XmlRes int resid,
- ApplicationInfo appInfo);
+ @Nullable
+ public abstract XmlResourceParser getXml(@NonNull String packageName, @XmlRes int resid,
+ @Nullable ApplicationInfo appInfo);
/**
* Return the label to use for this application.
@@ -5113,7 +5193,8 @@
* it could not be found for any reason.
* @param info The application to get the label of.
*/
- public abstract CharSequence getApplicationLabel(ApplicationInfo info);
+ @NonNull
+ public abstract CharSequence getApplicationLabel(@NonNull ApplicationInfo info);
/**
* Retrieve the resources associated with an activity. Given the full
@@ -5130,7 +5211,8 @@
*
* @see #getResourcesForApplication(ApplicationInfo)
*/
- public abstract Resources getResourcesForActivity(ComponentName activityName)
+ @NonNull
+ public abstract Resources getResourcesForActivity(@NonNull ComponentName activityName)
throws NameNotFoundException;
/**
@@ -5143,7 +5225,8 @@
* @throws NameNotFoundException Thrown if the resources for the given
* application could not be loaded (most likely because it was uninstalled).
*/
- public abstract Resources getResourcesForApplication(ApplicationInfo app)
+ @NonNull
+ public abstract Resources getResourcesForApplication(@NonNull ApplicationInfo app)
throws NameNotFoundException;
/**
@@ -5152,7 +5235,7 @@
* calls getResources() to return its application's resources. If the
* appPackageName cannot be found, NameNotFoundException is thrown.
*
- * @param appPackageName Package name of the application whose resources
+ * @param packageName Package name of the application whose resources
* are to be retrieved.
*
* @return Returns the application's Resources.
@@ -5161,12 +5244,14 @@
*
* @see #getResourcesForApplication(ApplicationInfo)
*/
- public abstract Resources getResourcesForApplication(String appPackageName)
+ @NonNull
+ public abstract Resources getResourcesForApplication(@NonNull String packageName)
throws NameNotFoundException;
/** @hide */
+ @NonNull
@UnsupportedAppUsage
- public abstract Resources getResourcesForApplicationAsUser(String appPackageName,
+ public abstract Resources getResourcesForApplicationAsUser(@NonNull String packageName,
@UserIdInt int userId) throws NameNotFoundException;
/**
@@ -5178,7 +5263,9 @@
* @return A PackageInfo object containing information about the package
* archive. If the package could not be parsed, returns null.
*/
- public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) {
+ @Nullable
+ public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
+ @PackageInfoFlags int flags) {
final PackageParser parser = new PackageParser();
parser.setCallback(new PackageParser.CallbackImpl(this));
final File apkFile = new File(archiveFilePath);
@@ -5212,7 +5299,8 @@
*/
@Deprecated
@SystemApi
- public abstract int installExistingPackage(String packageName) throws NameNotFoundException;
+ public abstract int installExistingPackage(@NonNull String packageName)
+ throws NameNotFoundException;
/**
* If there is already an application with the given package name installed
@@ -5223,8 +5311,8 @@
*/
@Deprecated
@SystemApi
- public abstract int installExistingPackage(String packageName, @InstallReason int installReason)
- throws NameNotFoundException;
+ public abstract int installExistingPackage(@NonNull String packageName,
+ @InstallReason int installReason) throws NameNotFoundException;
/**
* If there is already an application with the given package name installed
@@ -5239,8 +5327,8 @@
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.INTERACT_ACROSS_USERS_FULL})
@UnsupportedAppUsage
- public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId)
- throws NameNotFoundException;
+ public abstract int installExistingPackageAsUser(@NonNull String packageName,
+ @UserIdInt int userId) throws NameNotFoundException;
/**
* Allows a package listening to the
@@ -5316,7 +5404,7 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT)
public abstract void verifyIntentFilter(int verificationId, int verificationCode,
- List<String> failedDomains);
+ @NonNull List<String> failedDomains);
/**
* Get the status of a Domain Verification Result for an IntentFilter. This is
@@ -5340,7 +5428,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- public abstract int getIntentVerificationStatusAsUser(String packageName, @UserIdInt int userId);
+ public abstract int getIntentVerificationStatusAsUser(@NonNull String packageName,
+ @UserIdInt int userId);
/**
* Allow to change the status of a Intent Verification status for all IntentFilter of an App.
@@ -5364,8 +5453,8 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
- public abstract boolean updateIntentVerificationStatusAsUser(String packageName, int status,
- @UserIdInt int userId);
+ public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String packageName,
+ int status, @UserIdInt int userId);
/**
* Get the list of IntentFilterVerificationInfo for a specific package and User.
@@ -5379,9 +5468,10 @@
*
* @hide
*/
+ @NonNull
@SystemApi
public abstract List<IntentFilterVerificationInfo> getIntentFilterVerifications(
- String packageName);
+ @NonNull String packageName);
/**
* Get the list of IntentFilter for a specific package.
@@ -5394,8 +5484,9 @@
*
* @hide
*/
+ @NonNull
@SystemApi
- public abstract List<IntentFilter> getAllIntentFilters(String packageName);
+ public abstract List<IntentFilter> getAllIntentFilters(@NonNull String packageName);
/**
* Get the default Browser package name for a specific user.
@@ -5407,6 +5498,7 @@
*
* @hide
*/
+ @Nullable
@TestApi
@SystemApi
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@@ -5428,7 +5520,7 @@
@RequiresPermission(allOf = {
Manifest.permission.SET_PREFERRED_APPLICATIONS,
Manifest.permission.INTERACT_ACROSS_USERS_FULL})
- public abstract boolean setDefaultBrowserPackageNameAsUser(String packageName,
+ public abstract boolean setDefaultBrowserPackageNameAsUser(@Nullable String packageName,
@UserIdInt int userId);
/**
@@ -5446,13 +5538,13 @@
* @param installerPackageName The package name of the new installer. May be
* null to clear the association.
*/
- public abstract void setInstallerPackageName(String targetPackage,
- String installerPackageName);
+ public abstract void setInstallerPackageName(@NonNull String targetPackage,
+ @Nullable String installerPackageName);
/** @hide */
@SystemApi
@RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
- public abstract void setUpdateAvailable(String packageName, boolean updateAvaialble);
+ public abstract void setUpdateAvailable(@NonNull String packageName, boolean updateAvaialble);
/**
* Attempts to delete a package. Since this may take a little while, the
@@ -5472,8 +5564,8 @@
*/
@RequiresPermission(Manifest.permission.DELETE_PACKAGES)
@UnsupportedAppUsage
- public abstract void deletePackage(String packageName, IPackageDeleteObserver observer,
- @DeleteFlags int flags);
+ public abstract void deletePackage(@NonNull String packageName,
+ @Nullable IPackageDeleteObserver observer, @DeleteFlags int flags);
/**
* Attempts to delete a package. Since this may take a little while, the
@@ -5495,7 +5587,8 @@
Manifest.permission.INTERACT_ACROSS_USERS_FULL})
@UnsupportedAppUsage
public abstract void deletePackageAsUser(@NonNull String packageName,
- IPackageDeleteObserver observer, @DeleteFlags int flags, @UserIdInt int userId);
+ @Nullable IPackageDeleteObserver observer, @DeleteFlags int flags,
+ @UserIdInt int userId);
/**
* Retrieve the package name of the application that installed a package. This identifies
@@ -5505,7 +5598,7 @@
* @throws IllegalArgumentException if the given package name is not installed
*/
@Nullable
- public abstract String getInstallerPackageName(String packageName);
+ public abstract String getInstallerPackageName(@NonNull String packageName);
/**
* Attempts to clear the user data directory of an application.
@@ -5522,8 +5615,8 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract void clearApplicationUserData(String packageName,
- IPackageDataObserver observer);
+ public abstract void clearApplicationUserData(@NonNull String packageName,
+ @Nullable IPackageDataObserver observer);
/**
* Attempts to delete the cache files associated with an application.
* Since this may take a little while, the result will
@@ -5541,8 +5634,8 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract void deleteApplicationCacheFiles(String packageName,
- IPackageDataObserver observer);
+ public abstract void deleteApplicationCacheFiles(@NonNull String packageName,
+ @Nullable IPackageDataObserver observer);
/**
* Attempts to delete the cache files associated with an application for a given user. Since
@@ -5563,8 +5656,8 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract void deleteApplicationCacheFilesAsUser(String packageName, int userId,
- IPackageDataObserver observer);
+ public abstract void deleteApplicationCacheFilesAsUser(@NonNull String packageName,
+ @UserIdInt int userId, @Nullable IPackageDataObserver observer);
/**
* Free storage by deleting LRU sorted list of cache files across
@@ -5589,14 +5682,15 @@
* @hide
*/
@UnsupportedAppUsage
- public void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer) {
+ public void freeStorageAndNotify(long freeStorageSize,
+ @Nullable IPackageDataObserver observer) {
freeStorageAndNotify(null, freeStorageSize, observer);
}
/** {@hide} */
@UnsupportedAppUsage
- public abstract void freeStorageAndNotify(String volumeUuid, long freeStorageSize,
- IPackageDataObserver observer);
+ public abstract void freeStorageAndNotify(@Nullable String volumeUuid, long freeStorageSize,
+ @Nullable IPackageDataObserver observer);
/**
* Free storage by deleting LRU sorted list of cache files across
@@ -5622,13 +5716,14 @@
* @hide
*/
@UnsupportedAppUsage
- public void freeStorage(long freeStorageSize, IntentSender pi) {
+ public void freeStorage(long freeStorageSize, @Nullable IntentSender pi) {
freeStorage(null, freeStorageSize, pi);
}
/** {@hide} */
@UnsupportedAppUsage
- public abstract void freeStorage(String volumeUuid, long freeStorageSize, IntentSender pi);
+ public abstract void freeStorage(@Nullable String volumeUuid, long freeStorageSize,
+ @Nullable IntentSender pi);
/**
* Retrieve the size information for a package.
@@ -5651,8 +5746,8 @@
*/
@Deprecated
@UnsupportedAppUsage
- public abstract void getPackageSizeInfoAsUser(String packageName, @UserIdInt int userId,
- IPackageStatsObserver observer);
+ public abstract void getPackageSizeInfoAsUser(@NonNull String packageName,
+ @UserIdInt int userId, @Nullable IPackageStatsObserver observer);
/**
* Like {@link #getPackageSizeInfoAsUser(String, int, IPackageStatsObserver)}, but
@@ -5663,7 +5758,7 @@
*/
@Deprecated
@UnsupportedAppUsage
- public void getPackageSizeInfo(String packageName, IPackageStatsObserver observer) {
+ public void getPackageSizeInfo(@NonNull String packageName, IPackageStatsObserver observer) {
getPackageSizeInfoAsUser(packageName, getUserId(), observer);
}
@@ -5676,7 +5771,7 @@
* holders, see {@link android.app.role.RoleManager}.
*/
@Deprecated
- public abstract void addPackageToPreferred(String packageName);
+ public abstract void addPackageToPreferred(@NonNull String packageName);
/**
* @deprecated This function no longer does anything. It is the platform's
@@ -5687,7 +5782,7 @@
* holders, see {@link android.app.role.RoleManager}.
*/
@Deprecated
- public abstract void removePackageFromPreferred(String packageName);
+ public abstract void removePackageFromPreferred(@NonNull String packageName);
/**
* Retrieve the list of all currently configured preferred packages. The
@@ -5705,6 +5800,7 @@
* an app to be responsible for a particular role and to check current role
* holders, see {@link android.app.role.RoleManager}.
*/
+ @NonNull
@Deprecated
public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
@@ -5731,8 +5827,8 @@
* holders, see {@link android.app.role.RoleManager}.
*/
@Deprecated
- public abstract void addPreferredActivity(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity);
+ public abstract void addPreferredActivity(@NonNull IntentFilter filter, int match,
+ @Nullable ComponentName[] set, @NonNull ComponentName activity);
/**
* Same as {@link #addPreferredActivity(IntentFilter, int,
@@ -5749,8 +5845,8 @@
*/
@Deprecated
@UnsupportedAppUsage
- public void addPreferredActivityAsUser(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, @UserIdInt int userId) {
+ public void addPreferredActivityAsUser(@NonNull IntentFilter filter, int match,
+ @Nullable ComponentName[] set, @NonNull ComponentName activity, @UserIdInt int userId) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -5781,8 +5877,8 @@
*/
@Deprecated
@UnsupportedAppUsage
- public abstract void replacePreferredActivity(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity);
+ public abstract void replacePreferredActivity(@NonNull IntentFilter filter, int match,
+ @Nullable ComponentName[] set, @NonNull ComponentName activity);
/**
* Replaces an existing preferred activity mapping to the system, and if that were not present
@@ -5826,8 +5922,8 @@
*/
@Deprecated
@UnsupportedAppUsage
- public void replacePreferredActivityAsUser(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, @UserIdInt int userId) {
+ public void replacePreferredActivityAsUser(@NonNull IntentFilter filter, int match,
+ @Nullable ComponentName[] set, @NonNull ComponentName activity, @UserIdInt int userId) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -5848,7 +5944,7 @@
* holders, see {@link android.app.role.RoleManager}.
*/
@Deprecated
- public abstract void clearPackagePreferredActivities(String packageName);
+ public abstract void clearPackagePreferredActivities(@NonNull String packageName);
/**
* Retrieve all preferred activities, previously added with
@@ -5876,15 +5972,16 @@
*/
@Deprecated
public abstract int getPreferredActivities(@NonNull List<IntentFilter> outFilters,
- @NonNull List<ComponentName> outActivities, String packageName);
+ @NonNull List<ComponentName> outActivities, @Nullable String packageName);
/**
* Ask for the set of available 'home' activities and the current explicit
* default, if any.
* @hide
*/
+ @Nullable
@UnsupportedAppUsage
- public abstract ComponentName getHomeActivities(List<ResolveInfo> outActivities);
+ public abstract ComponentName getHomeActivities(@NonNull List<ResolveInfo> outActivities);
/**
* Set the enabled setting for a package component (activity, receiver, service, provider).
@@ -5984,7 +6081,7 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract void flushPackageRestrictionsAsUser(int userId);
+ public abstract void flushPackageRestrictionsAsUser(@UserIdInt int userId);
/**
* Puts the package in a hidden state, which is almost like an uninstalled state,
@@ -5994,8 +6091,8 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
- UserHandle userHandle);
+ public abstract boolean setApplicationHiddenSettingAsUser(@NonNull String packageName,
+ boolean hidden, @NonNull UserHandle userHandle);
/**
* Returns the hidden state of a package.
@@ -6003,8 +6100,8 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract boolean getApplicationHiddenSettingAsUser(String packageName,
- UserHandle userHandle);
+ public abstract boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
+ @NonNull UserHandle userHandle);
/**
* Return whether the device has been booted into safe mode.
@@ -6020,7 +6117,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
- public abstract void addOnPermissionsChangeListener(OnPermissionsChangedListener listener);
+ public abstract void addOnPermissionsChangeListener(
+ @NonNull OnPermissionsChangedListener listener);
/**
* Remvoes a listener for permission changes for installed packages.
@@ -6031,7 +6129,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
- public abstract void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener);
+ public abstract void removeOnPermissionsChangeListener(
+ @NonNull OnPermissionsChangedListener listener);
/**
* Return the {@link KeySet} associated with the String alias for this
@@ -6041,14 +6140,16 @@
* application's AndroidManifest.xml.
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
- public abstract KeySet getKeySetByAlias(String packageName, String alias);
+ public abstract KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias);
/** Return the signing {@link KeySet} for this application.
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
- public abstract KeySet getSigningKeySet(String packageName);
+ public abstract KeySet getSigningKeySet(@NonNull String packageName);
/**
* Return whether the package denoted by packageName has been signed by all
@@ -6058,7 +6159,7 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract boolean isSignedBy(String packageName, KeySet ks);
+ public abstract boolean isSignedBy(@NonNull String packageName, @NonNull KeySet ks);
/**
* Return whether the package denoted by packageName has been signed by all
@@ -6067,7 +6168,7 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract boolean isSignedByExactly(String packageName, KeySet ks);
+ public abstract boolean isSignedByExactly(@NonNull String packageName, @NonNull KeySet ks);
/**
* Flag to denote no restrictions. This should be used to clear any restrictions that may have
@@ -6284,7 +6385,7 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract boolean isPackageSuspendedForUser(String packageName, int userId);
+ public abstract boolean isPackageSuspendedForUser(@NonNull String packageName, int userId);
/**
* Query if an app is currently suspended.
@@ -6294,7 +6395,7 @@
*
* @see #isPackageSuspended()
*/
- public boolean isPackageSuspended(String packageName) throws NameNotFoundException {
+ public boolean isPackageSuspended(@NonNull String packageName) throws NameNotFoundException {
throw new UnsupportedOperationException("isPackageSuspended not implemented");
}
@@ -6378,23 +6479,26 @@
/** {@hide} */
@UnsupportedAppUsage
- public abstract void registerMoveCallback(MoveCallback callback, Handler handler);
+ public abstract void registerMoveCallback(@NonNull MoveCallback callback,
+ @NonNull Handler handler);
/** {@hide} */
@UnsupportedAppUsage
- public abstract void unregisterMoveCallback(MoveCallback callback);
+ public abstract void unregisterMoveCallback(@NonNull MoveCallback callback);
/** {@hide} */
@UnsupportedAppUsage
- public abstract int movePackage(String packageName, VolumeInfo vol);
+ public abstract int movePackage(@NonNull String packageName, @NonNull VolumeInfo vol);
/** {@hide} */
@UnsupportedAppUsage
- public abstract @Nullable VolumeInfo getPackageCurrentVolume(ApplicationInfo app);
+ public abstract @Nullable VolumeInfo getPackageCurrentVolume(@NonNull ApplicationInfo app);
/** {@hide} */
+ @NonNull
@UnsupportedAppUsage
- public abstract @NonNull List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app);
+ public abstract List<VolumeInfo> getPackageCandidateVolumes(
+ @NonNull ApplicationInfo app);
/** {@hide} */
- public abstract int movePrimaryStorage(VolumeInfo vol);
+ public abstract int movePrimaryStorage(@NonNull VolumeInfo vol);
/** {@hide} */
public abstract @Nullable VolumeInfo getPrimaryStorageCurrentVolume();
/** {@hide} */
@@ -6407,6 +6511,7 @@
* @return identity that uniquely identifies current device
* @hide
*/
+ @NonNull
public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
/**
@@ -6437,8 +6542,8 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId,
- int targetUserId, int flags);
+ public abstract void addCrossProfileIntentFilter(@NonNull IntentFilter filter,
+ @UserIdInt int sourceUserId, @UserIdInt int targetUserId, int flags);
/**
* Clearing {@code CrossProfileIntentFilter}s which have the specified user
@@ -6448,27 +6553,32 @@
* @hide
*/
@UnsupportedAppUsage
- public abstract void clearCrossProfileIntentFilters(int sourceUserId);
+ public abstract void clearCrossProfileIntentFilters(@UserIdInt int sourceUserId);
/**
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
- public abstract Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo);
+ public abstract Drawable loadItemIcon(@NonNull PackageItemInfo itemInfo,
+ @Nullable ApplicationInfo appInfo);
/**
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
- public abstract Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo);
+ public abstract Drawable loadUnbadgedItemIcon(@NonNull PackageItemInfo itemInfo,
+ @Nullable ApplicationInfo appInfo);
/** {@hide} */
@UnsupportedAppUsage
- public abstract boolean isPackageAvailable(String packageName);
+ public abstract boolean isPackageAvailable(@NonNull String packageName);
/** {@hide} */
+ @NonNull
@UnsupportedAppUsage
- public static String installStatusToString(int status, String msg) {
+ public static String installStatusToString(int status, @Nullable String msg) {
final String str = installStatusToString(status);
if (msg != null) {
return str + ": " + msg;
@@ -6478,6 +6588,7 @@
}
/** {@hide} */
+ @NonNull
@UnsupportedAppUsage
public static String installStatusToString(int status) {
switch (status) {
@@ -6582,7 +6693,8 @@
}
/** {@hide} */
- public static String deleteStatusToString(int status, String msg) {
+ @NonNull
+ public static String deleteStatusToString(int status, @Nullable String msg) {
final String str = deleteStatusToString(status);
if (msg != null) {
return str + ": " + msg;
@@ -6592,6 +6704,7 @@
}
/** {@hide} */
+ @NonNull
@UnsupportedAppUsage
public static String deleteStatusToString(int status) {
switch (status) {
@@ -6621,6 +6734,7 @@
}
/** {@hide} */
+ @NonNull
public static String permissionFlagToString(int flag) {
switch (flag) {
case FLAG_PERMISSION_GRANTED_BY_DEFAULT: return "GRANTED_BY_DEFAULT";
@@ -6668,8 +6782,8 @@
* @hide
*/
@TestApi
- public abstract @InstallReason int getInstallReason(String packageName,
- @NonNull UserHandle user);
+ @InstallReason
+ public abstract int getInstallReason(@NonNull String packageName, @NonNull UserHandle user);
/**
* Checks whether the calling package is allowed to request package installs through package
@@ -6695,6 +6809,7 @@
* @see {@link android.content.Intent#ACTION_INSTANT_APP_RESOLVER_SETTINGS}
* @hide
*/
+ @Nullable
@SystemApi
public abstract ComponentName getInstantAppResolverSettingsComponent();
@@ -6705,6 +6820,7 @@
* @see {@link android.content.Intent#ACTION_INSTALL_INSTANT_APP_PACKAGE}
* @hide
*/
+ @Nullable
@SystemApi
public abstract ComponentName getInstantAppInstallerComponent();
@@ -6714,7 +6830,9 @@
* @see {@link android.provider.Settings.Secure#ANDROID_ID}
* @hide
*/
- public abstract String getInstantAppAndroidId(String packageName, @NonNull UserHandle user);
+ @Nullable
+ public abstract String getInstantAppAndroidId(@NonNull String packageName,
+ @NonNull UserHandle user);
/**
* Callback use to notify the callers of module registration that the operation
@@ -6757,7 +6875,7 @@
* @hide
*/
@SystemApi
- public abstract void registerDexModule(String dexModulePath,
+ public abstract void registerDexModule(@NonNull String dexModulePath,
@Nullable DexModuleRegisterCallback callback);
/**
@@ -6837,8 +6955,8 @@
* @param type representation of the {@code certificate}
* @return true if this package was or is signed by exactly the certificate {@code certificate}
*/
- public boolean hasSigningCertificate(
- String packageName, byte[] certificate, @CertificateInputType int type) {
+ public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
+ @CertificateInputType int type) {
throw new UnsupportedOperationException(
"hasSigningCertificate not implemented in subclass");
}
@@ -6862,7 +6980,7 @@
* @return true if this package was or is signed by exactly the certificate {@code certificate}
*/
public boolean hasSigningCertificate(
- int uid, byte[] certificate, @CertificateInputType int type) {
+ int uid, @NonNull byte[] certificate, @CertificateInputType int type) {
throw new UnsupportedOperationException(
"hasSigningCertificate not implemented in subclass");
}
@@ -6872,16 +6990,28 @@
*
* @hide
*/
+ @Nullable
public String getSystemTextClassifierPackageName() {
throw new UnsupportedOperationException(
"getSystemTextClassifierPackageName not implemented in subclass");
}
/**
+ * @return attention service package name, or null if there's none.
+ *
+ * @hide
+ */
+ public String getAttentionServicePackageName() {
+ throw new UnsupportedOperationException(
+ "getAttentionServicePackageName not implemented in subclass");
+ }
+
+ /**
* @return the wellbeing app package name, or null if it's not defined by the OEM.
*
* @hide
*/
+ @Nullable
@TestApi
public String getWellbeingPackageName() {
throw new UnsupportedOperationException(
@@ -6893,6 +7023,7 @@
*
* @hide
*/
+ @Nullable
public String getAppPredictionServicePackageName() {
throw new UnsupportedOperationException(
"getAppPredictionServicePackageName not implemented in subclass");
@@ -6903,6 +7034,7 @@
*
* @hide
*/
+ @Nullable
public String getSystemCaptionsServicePackageName() {
throw new UnsupportedOperationException(
"getSystemCaptionsServicePackageName not implemented in subclass");
@@ -6928,7 +7060,7 @@
*
* @hide
*/
- public boolean isPackageStateProtected(String packageName, int userId) {
+ public boolean isPackageStateProtected(@NonNull String packageName, @UserIdInt int userId) {
throw new UnsupportedOperationException(
"isPackageStateProtected not implemented in subclass");
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 35d1eac..0a01dcd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3689,6 +3689,12 @@
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE;
}
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestApplication_allowExternalStorageSandbox,
+ owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q)) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX;
+ }
+
ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0);
ai.minAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0);
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 49b4cb0..514015f 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1263,12 +1263,19 @@
*/
@UnsupportedAppUsage
public boolean isUpToDate() {
- for (ApkAssets apkAssets : getApkAssets()) {
- if (!apkAssets.isUpToDate()) {
+ synchronized (this) {
+ if (!mOpen) {
return false;
}
+
+ for (ApkAssets apkAssets : mApkAssets) {
+ if (!apkAssets.isUpToDate()) {
+ return false;
+ }
+ }
+
+ return true;
}
- return true;
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index bad80b8..014bc24 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -39,6 +39,7 @@
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@@ -47,11 +48,15 @@
*/
public class SQLiteQueryBuilder {
private static final String TAG = "SQLiteQueryBuilder";
+
private static final Pattern sLimitPattern =
Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
+ private static final Pattern sAggregationPattern = Pattern.compile(
+ "(?i)(AVG|COUNT|MAX|MIN|SUM|TOTAL)\\((.+)\\)");
private Map<String, String> mProjectionMap = null;
private List<Pattern> mProjectionGreylist = null;
+ private boolean mProjectionAggregationAllowed = false;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mTables = "";
@@ -203,6 +208,16 @@
return mProjectionGreylist;
}
+ /** {@hide} */
+ public void setProjectionAggregationAllowed(boolean projectionAggregationAllowed) {
+ mProjectionAggregationAllowed = projectionAggregationAllowed;
+ }
+
+ /** {@hide} */
+ public boolean isProjectionAggregationAllowed() {
+ return mProjectionAggregationAllowed;
+ }
+
/**
* Sets the cursor factory to be used for the query. You can use
* one factory for all queries on a database but it is normally
@@ -842,26 +857,48 @@
return query.toString();
}
+ private static @NonNull String maybeWithOperator(@Nullable String operator,
+ @NonNull String column) {
+ if (operator != null) {
+ return operator + "(" + column + ")";
+ } else {
+ return column;
+ }
+ }
+
+ /** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private String[] computeProjection(String[] projectionIn) {
+ public String[] computeProjection(String[] projectionIn) {
if (projectionIn != null && projectionIn.length > 0) {
if (mProjectionMap != null) {
String[] projection = new String[projectionIn.length];
int length = projectionIn.length;
for (int i = 0; i < length; i++) {
+ String operator = null;
String userColumn = projectionIn[i];
String column = mProjectionMap.get(userColumn);
+ // If aggregation is allowed, extract the underlying column
+ // that may be aggregated
+ if (mProjectionAggregationAllowed) {
+ final Matcher matcher = sAggregationPattern.matcher(userColumn);
+ if (matcher.matches()) {
+ operator = matcher.group(1);
+ userColumn = matcher.group(2);
+ column = mProjectionMap.get(userColumn);
+ }
+ }
+
if (column != null) {
- projection[i] = column;
+ projection[i] = maybeWithOperator(operator, column);
continue;
}
if (!mStrict &&
( userColumn.contains(" AS ") || userColumn.contains(" as "))) {
/* A column alias already exist */
- projection[i] = userColumn;
+ projection[i] = maybeWithOperator(operator, userColumn);
continue;
}
@@ -878,7 +915,7 @@
if (match) {
Log.w(TAG, "Allowing abusive custom column: " + userColumn);
- projection[i] = userColumn;
+ projection[i] = maybeWithOperator(operator, userColumn);
continue;
}
}
@@ -911,7 +948,8 @@
return null;
}
- private @Nullable String computeWhere(@Nullable String selection) {
+ /** {@hide} */
+ public @Nullable String computeWhere(@Nullable String selection) {
final boolean hasInternal = !TextUtils.isEmpty(mWhereClause);
final boolean hasExternal = !TextUtils.isEmpty(selection);
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 5980251..06c32c6 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -22,6 +22,10 @@
import static android.net.NetworkUtils.resNetworkSend;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_DGRAM;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -30,12 +34,18 @@
import android.os.CancellationSignal;
import android.os.Looper;
import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
+import libcore.io.IoUtils;
+
import java.io.FileDescriptor;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
@@ -52,6 +62,7 @@
private static final String TAG = "DnsResolver";
private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
private static final int MAXPACKET = 8 * 1024;
+ private static final int SLEEP_TIME_MS = 2;
@IntDef(prefix = { "CLASS_" }, value = {
CLASS_IN
@@ -188,9 +199,9 @@
* Send a raw DNS query.
* The answer will be provided asynchronously through the provided {@link AnswerCallback}.
*
- * @param network {@link Network} specifying which network for querying.
+ * @param network {@link Network} specifying which network to query on.
* {@code null} for query on default network.
- * @param query blob message
+ * @param query blob message to query
* @param flags flags as a combination of the FLAGS_* constants
* @param executor The {@link Executor} that the callback should be executed on.
* @param cancellationSignal used by the caller to signal if the query should be
@@ -205,26 +216,32 @@
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
return;
}
+ final Object lock = new Object();
final FileDescriptor queryfd;
try {
queryfd = resNetworkSend((network != null
? network.netId : NETID_UNSET), query, query.length, flags);
} catch (ErrnoException e) {
- callback.onQueryException(e);
+ executor.execute(() -> {
+ callback.onQueryException(e);
+ });
return;
}
- maybeAddCancellationSignal(cancellationSignal, queryfd);
- registerFDListener(executor, queryfd, callback);
+ synchronized (lock) {
+ registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
+ if (cancellationSignal == null) return;
+ addCancellationSignal(cancellationSignal, queryfd, lock);
+ }
}
/**
* Send a DNS query with the specified name, class and query type.
* The answer will be provided asynchronously through the provided {@link AnswerCallback}.
*
- * @param network {@link Network} specifying which network for querying.
+ * @param network {@link Network} specifying which network to query on.
* {@code null} for query on default network.
- * @param domain domain name for querying
+ * @param domain domain name to query
* @param nsClass dns class as one of the CLASS_* constants
* @param nsType dns resource record (RR) type as one of the TYPE_* constants
* @param flags flags as a combination of the FLAGS_* constants
@@ -242,40 +259,187 @@
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
return;
}
+ final Object lock = new Object();
final FileDescriptor queryfd;
try {
queryfd = resNetworkQuery((network != null
? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
} catch (ErrnoException e) {
- callback.onQueryException(e);
+ executor.execute(() -> {
+ callback.onQueryException(e);
+ });
return;
}
+ synchronized (lock) {
+ registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
+ if (cancellationSignal == null) return;
+ addCancellationSignal(cancellationSignal, queryfd, lock);
+ }
+ }
- maybeAddCancellationSignal(cancellationSignal, queryfd);
- registerFDListener(executor, queryfd, callback);
+ private class InetAddressAnswerAccumulator extends InetAddressAnswerCallback {
+ private final List<InetAddress> mAllAnswers;
+ private ParseException mParseException;
+ private ErrnoException mErrnoException;
+ private final InetAddressAnswerCallback mUserCallback;
+ private final int mTargetAnswerCount;
+ private int mReceivedAnswerCount = 0;
+
+ InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerCallback callback) {
+ mTargetAnswerCount = size;
+ mAllAnswers = new ArrayList<>();
+ mUserCallback = callback;
+ }
+
+ private boolean maybeReportException() {
+ if (mErrnoException != null) {
+ mUserCallback.onQueryException(mErrnoException);
+ return true;
+ }
+ if (mParseException != null) {
+ mUserCallback.onParseException(mParseException);
+ return true;
+ }
+ return false;
+ }
+
+ private void maybeReportAnswer() {
+ if (++mReceivedAnswerCount != mTargetAnswerCount) return;
+ if (mAllAnswers.isEmpty() && maybeReportException()) return;
+ // TODO: Do RFC6724 sort.
+ mUserCallback.onAnswer(mAllAnswers);
+ }
+
+ @Override
+ public void onAnswer(@NonNull List<InetAddress> answer) {
+ mAllAnswers.addAll(answer);
+ maybeReportAnswer();
+ }
+
+ @Override
+ public void onParseException(@NonNull ParseException e) {
+ mParseException = e;
+ maybeReportAnswer();
+ }
+
+ @Override
+ public void onQueryException(@NonNull ErrnoException e) {
+ mErrnoException = e;
+ maybeReportAnswer();
+ }
+ }
+
+ /**
+ * Send a DNS query with the specified name, get back a set of InetAddresses asynchronously.
+ * The answer will be provided asynchronously through the provided
+ * {@link InetAddressAnswerCallback}.
+ *
+ * @param network {@link Network} specifying which network to query on.
+ * {@code null} for query on default network.
+ * @param domain domain name to query
+ * @param flags flags as a combination of the FLAGS_* constants
+ * @param executor The {@link Executor} that the callback should be executed on.
+ * @param cancellationSignal used by the caller to signal if the query should be
+ * cancelled. May be {@code null}.
+ * @param callback an {@link InetAddressAnswerCallback} which will be called to notify the
+ * caller of the result of dns query.
+ */
+ public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
+ @NonNull @CallbackExecutor Executor executor,
+ @Nullable CancellationSignal cancellationSignal,
+ @NonNull InetAddressAnswerCallback callback) {
+ if (cancellationSignal != null && cancellationSignal.isCanceled()) {
+ return;
+ }
+ final Object lock = new Object();
+ final boolean queryIpv6 = haveIpv6(network);
+ final boolean queryIpv4 = haveIpv4(network);
+
+ final FileDescriptor v4fd;
+ final FileDescriptor v6fd;
+
+ int queryCount = 0;
+
+ if (queryIpv6) {
+ try {
+ v6fd = resNetworkQuery((network != null
+ ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
+ } catch (ErrnoException e) {
+ executor.execute(() -> {
+ callback.onQueryException(e);
+ });
+ return;
+ }
+ queryCount++;
+ } else v6fd = null;
+
+ // TODO: Use device flag to control the sleep time.
+ // Avoiding gateways drop packets if queries are sent too close together
+ try {
+ Thread.sleep(SLEEP_TIME_MS);
+ } catch (InterruptedException ex) { }
+
+ if (queryIpv4) {
+ try {
+ v4fd = resNetworkQuery((network != null
+ ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
+ } catch (ErrnoException e) {
+ if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid.
+ executor.execute(() -> {
+ callback.onQueryException(e);
+ });
+ return;
+ }
+ queryCount++;
+ } else v4fd = null;
+
+ final InetAddressAnswerAccumulator accumulator =
+ new InetAddressAnswerAccumulator(queryCount, callback);
+
+ synchronized (lock) {
+ if (queryIpv6) {
+ registerFDListener(executor, v6fd, accumulator, cancellationSignal, lock);
+ }
+ if (queryIpv4) {
+ registerFDListener(executor, v4fd, accumulator, cancellationSignal, lock);
+ }
+ if (cancellationSignal == null) return;
+ cancellationSignal.setOnCancelListener(() -> {
+ synchronized (lock) {
+ if (queryIpv4) cancelQuery(v4fd);
+ if (queryIpv6) cancelQuery(v6fd);
+ }
+ });
+ }
}
private <T> void registerFDListener(@NonNull Executor executor,
- @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback) {
+ @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback,
+ @Nullable CancellationSignal cancellationSignal, @NonNull Object lock) {
Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
queryfd,
FD_EVENTS,
(fd, events) -> {
executor.execute(() -> {
- byte[] answerbuf = null;
- try {
- answerbuf = resNetworkResult(fd);
- } catch (ErrnoException e) {
- Log.e(TAG, "resNetworkResult:" + e.toString());
- answerCallback.onQueryException(e);
- return;
- }
+ synchronized (lock) {
+ if (cancellationSignal != null && cancellationSignal.isCanceled()) {
+ return;
+ }
+ byte[] answerbuf = null;
+ try {
+ answerbuf = resNetworkResult(fd); // Closes fd, marks it invalid.
+ } catch (ErrnoException e) {
+ Log.e(TAG, "resNetworkResult:" + e.toString());
+ answerCallback.onQueryException(e);
+ return;
+ }
- try {
- answerCallback.onAnswer(
- answerCallback.parser.parse(answerbuf));
- } catch (ParseException e) {
- answerCallback.onParseException(e);
+ try {
+ answerCallback.onAnswer(
+ answerCallback.parser.parse(answerbuf));
+ } catch (ParseException e) {
+ answerCallback.onParseException(e);
+ }
}
});
// Unregister this fd listener
@@ -283,15 +447,51 @@
});
}
- private void maybeAddCancellationSignal(@Nullable CancellationSignal cancellationSignal,
- @NonNull FileDescriptor queryfd) {
- if (cancellationSignal == null) return;
- cancellationSignal.setOnCancelListener(
- () -> {
- Looper.getMainLooper().getQueue()
- .removeOnFileDescriptorEventListener(queryfd);
- resNetworkCancel(queryfd);
- });
+ private void cancelQuery(@NonNull FileDescriptor queryfd) {
+ if (!queryfd.valid()) return;
+ Looper.getMainLooper().getQueue().removeOnFileDescriptorEventListener(queryfd);
+ resNetworkCancel(queryfd); // Closes fd, marks it invalid.
+ }
+
+ private void addCancellationSignal(@NonNull CancellationSignal cancellationSignal,
+ @NonNull FileDescriptor queryfd, @NonNull Object lock) {
+ cancellationSignal.setOnCancelListener(() -> {
+ synchronized (lock) {
+ cancelQuery(queryfd);
+ }
+ });
+ }
+
+ // These two functions match the behaviour of have_ipv4 and have_ipv6 in the native resolver.
+ private boolean haveIpv4(@Nullable Network network) {
+ final SocketAddress addrIpv4 =
+ new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0);
+ return checkConnectivity(network, AF_INET, addrIpv4);
+ }
+
+ private boolean haveIpv6(@Nullable Network network) {
+ final SocketAddress addrIpv6 =
+ new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0);
+ return checkConnectivity(network, AF_INET6, addrIpv6);
+ }
+
+ private boolean checkConnectivity(@Nullable Network network,
+ int domain, @NonNull SocketAddress addr) {
+ final FileDescriptor socket;
+ try {
+ socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP);
+ } catch (ErrnoException e) {
+ return false;
+ }
+ try {
+ if (network != null) network.bindSocket(socket);
+ Os.connect(socket, addr);
+ } catch (IOException | ErrnoException e) {
+ return false;
+ } finally {
+ IoUtils.closeQuietly(socket);
+ }
+ return true;
}
private static class DnsAddressAnswer extends DnsPacket {
diff --git a/core/java/android/os/BatterySaverPolicyConfig.java b/core/java/android/os/BatterySaverPolicyConfig.java
index bda4e27..879ab1e 100644
--- a/core/java/android/os/BatterySaverPolicyConfig.java
+++ b/core/java/android/os/BatterySaverPolicyConfig.java
@@ -58,7 +58,8 @@
mAdvertiseIsEnabled = in.mAdvertiseIsEnabled;
mDeferFullBackup = in.mDeferFullBackup;
mDeferKeyValueBackup = in.mDeferKeyValueBackup;
- mDeviceSpecificSettings = Collections.unmodifiableMap(in.mDeviceSpecificSettings);
+ mDeviceSpecificSettings = Collections.unmodifiableMap(
+ new ArrayMap<>(in.mDeviceSpecificSettings));
mDisableAnimation = in.mDisableAnimation;
mDisableAod = in.mDisableAod;
mDisableLaunchBoost = in.mDisableLaunchBoost;
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index cceb6ed..f7e927e 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -20,6 +20,8 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import android.app.AppGlobals;
+import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.storage.StorageManager;
@@ -1060,7 +1062,7 @@
* @throws IllegalArgumentException if the path is not a valid storage
* device.
*/
- public static boolean isExternalStorageRemovable(File path) {
+ public static boolean isExternalStorageRemovable(@NonNull File path) {
final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
if (volume != null) {
return volume.isRemovable();
@@ -1103,7 +1105,7 @@
* @throws IllegalArgumentException if the path is not a valid storage
* device.
*/
- public static boolean isExternalStorageEmulated(File path) {
+ public static boolean isExternalStorageEmulated(@NonNull File path) {
final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
if (volume != null) {
return volume.isEmulated();
@@ -1112,6 +1114,44 @@
}
}
+ /**
+ * Returns whether the shared/external storage media at the given path is a
+ * sandboxed view that only contains files owned by the app.
+ * <p>
+ * This value may be different from the value requested by
+ * {@code allowExternalStorageSandbox} in the app's manifest, since an app
+ * may inherit its sandboxed state based on when it was first installed.
+ * <p>
+ * Sandboxed apps can continue to discover and read media belonging to other
+ * apps via {@link android.provider.MediaStore}.
+ */
+ public static boolean isExternalStorageSandboxed() {
+ final File externalDir = sCurrentUser.getExternalDirs()[0];
+ return isExternalStorageSandboxed(externalDir);
+ }
+
+ /**
+ * Returns whether the shared/external storage media at the given path is a
+ * sandboxed view that only contains files owned by the app.
+ * <p>
+ * This value may be different from the value requested by
+ * {@code allowExternalStorageSandbox} in the app's manifest, since an app
+ * may inherit its sandboxed state based on when it was first installed.
+ * <p>
+ * Sandboxed apps can continue to discover and read media belonging to other
+ * apps via {@link android.provider.MediaStore}.
+ *
+ * @throws IllegalArgumentException if the path is not a valid storage
+ * device.
+ */
+ public static boolean isExternalStorageSandboxed(@NonNull File path) {
+ final Context context = AppGlobals.getInitialApplication();
+ final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
+ return appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
+ context.getApplicationInfo().uid,
+ context.getPackageName()) != AppOpsManager.MODE_ALLOWED;
+ }
+
static File getDirectory(String variableName, String defaultPath) {
String path = System.getenv(variableName);
return path == null ? new File(defaultPath) : new File(path);
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 6536fc9..03e8c15 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -330,12 +330,6 @@
*/
void removeIdleTimer(String iface);
- /**
- * Configure name servers, search paths, and resolver parameters for the given network.
- */
- void setDnsConfigurationForNetwork(int netId, in String[] servers, in String[] domains,
- in int[] params, String tlsHostname, in String[] tlsServers);
-
void setFirewallEnabled(boolean enabled);
boolean isFirewallEnabled();
void setFirewallInterfaceRule(String iface, boolean allow);
@@ -381,11 +375,6 @@
void createVirtualNetwork(int netId, boolean secure);
/**
- * Remove a network.
- */
- void removeNetwork(int netId);
-
- /**
* Add an interface to a network.
*/
void addInterfaceToNetwork(String iface, int netId);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 64e2f89..7d61bf6 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -773,8 +773,10 @@
*/
public static final int LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF = 4;
- static final int MIN_LOCATION_MODE = LOCATION_MODE_NO_CHANGE;
- static final int MAX_LOCATION_MODE = LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
+ /** @hide */
+ public static final int MIN_LOCATION_MODE = LOCATION_MODE_NO_CHANGE;
+ /** @hide */
+ public static final int MAX_LOCATION_MODE = LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
/**
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1cab250..5c2eacc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14726,7 +14726,6 @@
*
* @hide
*/
- // TODO(b/117663715): require a new write permission restricted to a single source
@RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
static void resetToDefaults(@NonNull ContentResolver resolver, @ResetMode int resetMode,
@Nullable String prefix) {
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index 6629233..af5bf74 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.Rlog;
import android.telephony.TelephonyManager;
import com.android.internal.telephony.uicc.IccUtils;
@@ -223,7 +224,7 @@
+ "mcc=" + mMcc
+ ",mnc=" + mMnc
+ ",spn=" + mSpn
- + ",imsi=" + mImsi
+ + ",imsi=" + Rlog.pii(false, mImsi)
+ ",gid1=" + mGid1
+ ",gid2=" + mGid2
+ ",carrierid=" + mCarrierId
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 7a35b9e..dc57a15 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -17,6 +17,8 @@
import static android.view.contentcapture.ContentCaptureHelper.sDebug;
import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
+import static android.view.contentcapture.ContentCaptureHelper.toList;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -36,9 +38,9 @@
import android.os.Looper;
import android.os.RemoteException;
import android.service.autofill.AutofillService;
-import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseIntArray;
import android.view.contentcapture.ContentCaptureCondition;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.ContentCaptureEvent;
@@ -53,7 +55,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -117,7 +118,7 @@
}
@Override
- public void onSessionStarted(ContentCaptureContext context, String sessionId, int uid,
+ public void onSessionStarted(ContentCaptureContext context, int sessionId, int uid,
IResultReceiver clientReceiver, int initialState) {
mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnCreateSession,
ContentCaptureService.this, context, sessionId, uid, clientReceiver,
@@ -125,14 +126,14 @@
}
@Override
- public void onActivitySnapshot(String sessionId, SnapshotData snapshotData) {
+ public void onActivitySnapshot(int sessionId, SnapshotData snapshotData) {
mHandler.sendMessage(
obtainMessage(ContentCaptureService::handleOnActivitySnapshot,
ContentCaptureService.this, sessionId, snapshotData));
}
@Override
- public void onSessionFinished(String sessionId) {
+ public void onSessionFinished(int sessionId) {
mHandler.sendMessage(obtainMessage(ContentCaptureService::handleFinishSession,
ContentCaptureService.this, sessionId));
}
@@ -171,7 +172,7 @@
* <p>This map is populated when an session is started, which is called by the system server
* and can be trusted. Then subsequent calls made by the app are verified against this map.
*/
- private final ArrayMap<String, Integer> mSessionUids = new ArrayMap<>();
+ private final SparseIntArray mSessionUids = new SparseIntArray();
@CallSuper
@Override
@@ -240,11 +241,17 @@
*/
public final void setContentCaptureConditions(@NonNull String packageName,
@Nullable Set<ContentCaptureCondition> conditions) {
- // TODO(b/129267994): implement
- }
+ final IContentCaptureServiceCallback callback = mCallback;
+ if (callback == null) {
+ Log.w(TAG, "setContentCaptureConditions(): no server callback");
+ return;
+ }
- private <T> ArrayList<T> toList(@Nullable Set<T> set) {
- return set == null ? null : new ArrayList<T>(set);
+ try {
+ callback.setContentCaptureConditions(packageName, toList(conditions));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
/**
@@ -378,7 +385,7 @@
// so we don't need to create a temporary InteractionSessionId for each event.
private void handleOnCreateSession(@NonNull ContentCaptureContext context,
- @NonNull String sessionId, int uid, IResultReceiver clientReceiver, int initialState) {
+ int sessionId, int uid, IResultReceiver clientReceiver, int initialState) {
mSessionUids.put(sessionId, uid);
onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId));
@@ -403,27 +410,27 @@
// Most events belong to the same session, so we can keep a reference to the last one
// to avoid creating too many ContentCaptureSessionId objects
- String lastSessionId = null;
+ int lastSessionId = NO_SESSION_ID;
ContentCaptureSessionId sessionId = null;
final List<ContentCaptureEvent> events = parceledEvents.getList();
for (int i = 0; i < events.size(); i++) {
final ContentCaptureEvent event = events.get(i);
if (!handleIsRightCallerFor(event, uid)) continue;
- String sessionIdString = event.getSessionId();
- if (!sessionIdString.equals(lastSessionId)) {
- sessionId = new ContentCaptureSessionId(sessionIdString);
- lastSessionId = sessionIdString;
+ int sessionIdInt = event.getSessionId();
+ if (sessionIdInt != lastSessionId) {
+ sessionId = new ContentCaptureSessionId(sessionIdInt);
+ lastSessionId = sessionIdInt;
}
switch (event.getType()) {
case ContentCaptureEvent.TYPE_SESSION_STARTED:
final ContentCaptureContext clientContext = event.getContentCaptureContext();
clientContext.setParentSessionId(event.getParentSessionId());
- mSessionUids.put(sessionIdString, uid);
+ mSessionUids.put(sessionIdInt, uid);
onCreateContentCaptureSession(clientContext, sessionId);
break;
case ContentCaptureEvent.TYPE_SESSION_FINISHED:
- mSessionUids.remove(sessionIdString);
+ mSessionUids.delete(sessionIdInt);
onDestroyContentCaptureSession(sessionId);
break;
default:
@@ -432,13 +439,12 @@
}
}
- private void handleOnActivitySnapshot(@NonNull String sessionId,
- @NonNull SnapshotData snapshotData) {
+ private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) {
onActivitySnapshot(new ContentCaptureSessionId(sessionId), snapshotData);
}
- private void handleFinishSession(@NonNull String sessionId) {
- mSessionUids.remove(sessionId);
+ private void handleFinishSession(int sessionId) {
+ mSessionUids.delete(sessionId);
onDestroyContentCaptureSession(new ContentCaptureSessionId(sessionId));
}
@@ -454,7 +460,7 @@
* Checks if the given {@code uid} owns the session associated with the event.
*/
private boolean handleIsRightCallerFor(@NonNull ContentCaptureEvent event, int uid) {
- final String sessionId;
+ final int sessionId;
switch (event.getType()) {
case ContentCaptureEvent.TYPE_SESSION_STARTED:
case ContentCaptureEvent.TYPE_SESSION_FINISHED:
@@ -463,8 +469,7 @@
default:
sessionId = event.getSessionId();
}
- final Integer rightUid = mSessionUids.get(sessionId);
- if (rightUid == null) {
+ if (mSessionUids.indexOfKey(sessionId) < 0) {
if (sVerbose) {
Log.v(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId
+ ": " + mSessionUids);
@@ -472,6 +477,7 @@
// Just ignore, as the session could have been finished already
return false;
}
+ final int rightUid = mSessionUids.get(sessionId);
if (rightUid != uid) {
Log.e(TAG, "invalid call from UID " + uid + ": session " + sessionId + " belongs to "
+ rightUid);
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
index 6be7a80..03e1b78 100644
--- a/core/java/android/service/contentcapture/IContentCaptureService.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -35,10 +35,10 @@
oneway interface IContentCaptureService {
void onConnected(IBinder callback, boolean verbose, boolean debug);
void onDisconnected();
- void onSessionStarted(in ContentCaptureContext context, String sessionId, int uid,
+ void onSessionStarted(in ContentCaptureContext context, int sessionId, int uid,
in IResultReceiver clientReceiver, int initialState);
- void onSessionFinished(String sessionId);
- void onActivitySnapshot(String sessionId, in SnapshotData snapshotData);
+ void onSessionFinished(int sessionId);
+ void onActivitySnapshot(int sessionId, in SnapshotData snapshotData);
void onUserDataRemovalRequest(in UserDataRemovalRequest request);
void onActivityEvent(in ActivityEvent event);
}
diff --git a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
index 8bc8def..0550ad3 100644
--- a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
@@ -17,6 +17,7 @@
package android.service.contentcapture;
import android.content.ComponentName;
+import android.view.contentcapture.ContentCaptureCondition;
import java.util.List;
@@ -27,5 +28,6 @@
*/
oneway interface IContentCaptureServiceCallback {
void setContentCaptureWhitelist(in List<String> packages, in List<ComponentName> activities);
+ void setContentCaptureConditions(String packageName, in List<ContentCaptureCondition> conditions);
void disableSelf();
}
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 610f7ed..715181f 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -512,8 +512,8 @@
* @hide
*/
public DisplayCutout inset(int insetLeft, int insetTop, int insetRight, int insetBottom) {
- if (isBoundsEmpty()
- || insetLeft == 0 && insetTop == 0 && insetRight == 0 && insetBottom == 0) {
+ if (insetLeft == 0 && insetTop == 0 && insetRight == 0 && insetBottom == 0
+ || isBoundsEmpty()) {
return this;
}
@@ -534,6 +534,12 @@
safeInsets.right = atLeastZero(safeInsets.right - insetRight);
}
+ // If we are not cutting off part of the cutout by insetting it on bottom/right, and we also
+ // don't move it around, we can avoid the allocation and copy of the instance.
+ if (insetLeft == 0 && insetTop == 0 && mSafeInsets.equals(safeInsets)) {
+ return this;
+ }
+
Rect[] bounds = mBounds.getRects();
for (int i = 0; i < bounds.length; ++i) {
if (!bounds[i].equals(ZERO_RECT)) {
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 87efb3f..d317df0 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -255,12 +255,11 @@
void updatePointerIcon(IWindow window);
/**
- * Update a tap exclude region with a rectangular area identified by provided id in the window.
- * Touches on this region will not switch focus to this window. Passing an empty rect will
- * remove the area from the exclude region of this window.
+ * Update a tap exclude region identified by provided id in the window. Touches on this region
+ * will neither be dispatched to this window nor change the focus to this window. Passing an
+ * invalid region will remove the area from the exclude region of this window.
*/
- void updateTapExcludeRegion(IWindow window, int regionId, int left, int top, int width,
- int height);
+ void updateTapExcludeRegion(IWindow window, int regionId, in Region region);
/**
* Called when the client has changed the local insets state, and now the server should reflect
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c34613e..24f4c14 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -86,7 +86,6 @@
import android.sysprop.DisplayProperties;
import android.text.InputType;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.LayoutDirection;
@@ -7956,6 +7955,8 @@
* View is not a pane.
*
* {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)}
+ *
+ * @attr ref android.R.styleable#View_accessibilityPaneTitle
*/
public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) {
if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) {
@@ -7971,6 +7972,8 @@
* @return The current pane title.
*
* {@see #setAccessibilityPaneTitle}.
+ *
+ * @attr ref android.R.styleable#View_accessibilityPaneTitle
*/
@InspectableProperty
@Nullable
@@ -8525,11 +8528,11 @@
}
/**
- * Populates a {@link ViewStructure} for Content Capture.
+ * Populates a {@link ViewStructure} for content capture.
*
- * <p>This method is called after a view is that is eligible for Content Capture
+ * <p>This method is called after a view is that is eligible for content capture
* (for example, if it {@link #isImportantForAutofill()}, an intelligence service is enabled for
- * the user, and the activity rendering the view is enabled for Content Capture) is laid out and
+ * the user, and the activity rendering the view is enabled for content capture) is laid out and
* is visible.
*
* <p>The populated structure is then passed to the service through
@@ -8548,6 +8551,16 @@
* {@code childStructure.getAutofillId()} or
* {@link ContentCaptureSession#newAutofillId(AutofillId, long)}.
*
+ * <p>When the virtual view hierarchy represents a web page, you should also:
+ *
+ * <ul>
+ * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content
+ * capture events should be generate for that URL.
+ * <li>Create a new {@link ContentCaptureSession} child for every HTML element that
+ * renders a new URL (like an {@code IFRAME}) and use that session to notify events from
+ * that subtree.
+ * </ul>
+ *
* <p><b>Note: </b>the following methods of the {@code structure} will be ignored:
* <ul>
* <li>{@link ViewStructure#setChildCount(int)}
@@ -9264,11 +9277,13 @@
}
/**
- * Hints the Android System whether this view is considered important for Content Capture, based
+ * Hints the Android System whether this view is considered important for content capture, based
* on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics
* when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}.
*
- * @return whether the view is considered important for autofill.
+ * <p>See {@link ContentCaptureManager} for more info about content capture.
+ *
+ * @return whether the view is considered important for content capture.
*
* @see #setImportantForContentCapture(int)
* @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO
@@ -9467,7 +9482,7 @@
* Sets the (optional) {@link ContentCaptureSession} associated with this view.
*
* <p>This method should be called when you need to associate a {@link ContentCaptureContext} to
- * the Content Capture events associated with this view or its view hierarchy (if it's a
+ * the content capture events associated with this view or its view hierarchy (if it's a
* {@link ViewGroup}).
*
* <p>For example, if your activity is associated with a web domain, first you would need to
@@ -9498,7 +9513,7 @@
}
/**
- * Gets the session used to notify Content Capture events.
+ * Gets the session used to notify content capture events.
*
* @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)},
* inherited by ancestors, default session or {@code null} if content capture is disabled for
@@ -9719,7 +9734,7 @@
}
/**
- * Dispatches the initial Content Capture events for a view structure.
+ * Dispatches the initial content capture events for a view structure.
*
* @hide
*/
@@ -12101,6 +12116,8 @@
* @see #setScreenReaderFocusable(boolean)
*
* @return Whether the view should be treated as a focusable unit by screen reader.
+ *
+ * @attr ref android.R.styleable#View_screenReaderFocusable
*/
@InspectableProperty
public boolean isScreenReaderFocusable() {
@@ -12119,6 +12136,8 @@
*
* @param screenReaderFocusable Whether the view should be treated as a unit by screen reader
* accessibility tools.
+ *
+ * @attr ref android.R.styleable#View_screenReaderFocusable
*/
public void setScreenReaderFocusable(boolean screenReaderFocusable) {
updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable);
@@ -13900,6 +13919,16 @@
}
/**
+ * Returns whether this view can receive pointer events.
+ *
+ * @return {@code true} if this view can receive pointer events.
+ * @hide
+ */
+ protected boolean canReceivePointerEvents() {
+ return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null;
+ }
+
+ /**
* Filter the touch event to apply security policies.
*
* @param event The motion event to be filtered.
@@ -17939,7 +17968,7 @@
final int scrollX = mScrollX;
final int scrollY = mScrollY;
invalidateInternal(dirty.left - scrollX, dirty.top - scrollY,
- dirty.right - scrollX, dirty.bottom - scrollY, true, false);
+ dirty.right - scrollX, dirty.bottom - scrollY, true);
}
/**
@@ -17965,7 +17994,7 @@
public void invalidate(int l, int t, int r, int b) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
- invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false);
+ invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true);
}
/**
@@ -17995,11 +18024,10 @@
*/
@UnsupportedAppUsage
public void invalidate(boolean invalidateCache) {
- invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
+ invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache);
}
- void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
- boolean fullInvalidate) {
+ void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache) {
if (mGhostView != null) {
mGhostView.invalidate(true);
return;
@@ -18016,11 +18044,9 @@
if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
|| (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
|| (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
- || (fullInvalidate && isOpaque() != mLastIsOpaque)) {
- if (fullInvalidate) {
- mLastIsOpaque = isOpaque();
- mPrivateFlags &= ~PFLAG_DRAWN;
- }
+ || isOpaque() != mLastIsOpaque) {
+ mLastIsOpaque = isOpaque();
+ mPrivateFlags &= ~PFLAG_DRAWN;
mPrivateFlags |= PFLAG_DIRTY;
@@ -22565,12 +22591,7 @@
@Override
public void invalidateDrawable(@NonNull Drawable drawable) {
if (verifyDrawable(drawable)) {
- final Rect dirty = drawable.getDirtyBounds();
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
-
- invalidate(dirty.left + scrollX, dirty.top + scrollY,
- dirty.right + scrollX, dirty.bottom + scrollY);
+ invalidate();
rebuildOutline();
}
}
@@ -28578,8 +28599,7 @@
* hierarchy is traversed: value is either the view itself for appearead events, or its
* autofill id for disappeared.
*/
- // TODO(b/121197119): use SparseArray once session id becomes integer
- ArrayMap<String, ArrayList<Object>> mContentCaptureEvents;
+ SparseArray<ArrayList<Object>> mContentCaptureEvents;
/**
* Cached reference to the {@link ContentCaptureManager}.
@@ -28609,9 +28629,9 @@
@NonNull View view, boolean appeared) {
if (mContentCaptureEvents == null) {
// Most of the time there will be just one session, so intial capacity is 1
- mContentCaptureEvents = new ArrayMap<>(1);
+ mContentCaptureEvents = new SparseArray<>(1);
}
- String sessionId = session.getId();
+ int sessionId = session.getId();
// TODO: life would be much easier if we provided a MultiMap implementation somwhere...
ArrayList<Object> events = mContentCaptureEvents.get(sessionId);
if (events == null) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4851476..937bd1b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2011,7 +2011,7 @@
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
- if (!canViewReceivePointerEvents(child)
+ if (!child.canReceivePointerEvents()
|| !isTransformedTouchPointInView(x, y, child, null)) {
continue;
}
@@ -2094,7 +2094,7 @@
childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(
preorderedList, children, childIndex);
- if (!canViewReceivePointerEvents(child)
+ if (!child.canReceivePointerEvents()
|| !isTransformedTouchPointInView(x, y, child, null)) {
continue;
}
@@ -2314,7 +2314,7 @@
getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View child =
getAndVerifyPreorderedView(preorderedList, children, childIndex);
- if (!canViewReceivePointerEvents(child)
+ if (!child.canReceivePointerEvents()
|| !isTransformedTouchPointInView(x, y, child, null)) {
continue;
}
@@ -2500,7 +2500,7 @@
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
- if (!canViewReceivePointerEvents(child)
+ if (!child.canReceivePointerEvents()
|| !isTransformedTouchPointInView(x, y, child, null)) {
continue;
}
@@ -2680,7 +2680,7 @@
i = childrenCount - 1;
}
- if (!canViewReceivePointerEvents(child)
+ if (!child.canReceivePointerEvents()
|| !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
@@ -2970,15 +2970,6 @@
}
}
- /**
- * Returns true if a child view can receive pointer events.
- * @hide
- */
- private static boolean canViewReceivePointerEvents(@NonNull View child) {
- return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
- || child.getAnimation() != null;
- }
-
private float[] getTempPoint() {
if (mTempPoint == null) {
mTempPoint = new float[2];
@@ -7199,6 +7190,46 @@
}
}
+ /**
+ * @hide
+ */
+ @Override
+ public void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
+ final int childrenCount = mChildrenCount;
+ final ArrayList<View> preorderedList = buildTouchDispatchChildList();
+ final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled();
+ final View[] children = mChildren;
+ for (int i = childrenCount - 1; i >= 0; i--) {
+ final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+ final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
+ if (child == view) {
+ // We've reached the target view.
+ break;
+ }
+ if (!child.canReceivePointerEvents()) {
+ // This child cannot be touched. Skip it.
+ continue;
+ }
+ applyOpToRegionByBounds(touchableRegion, child, Region.Op.DIFFERENCE);
+ }
+
+ // The touchable region should not exceed the bounds of its container.
+ applyOpToRegionByBounds(touchableRegion, this, Region.Op.INTERSECT);
+
+ final ViewParent parent = getParent();
+ if (parent != null) {
+ parent.subtractObscuredTouchableRegion(touchableRegion, this);
+ }
+ }
+
+ private static void applyOpToRegionByBounds(Region region, View view, Region.Op op) {
+ final int[] locationInWindow = new int[2];
+ view.getLocationInWindow(locationInWindow);
+ final int x = locationInWindow[0];
+ final int y = locationInWindow[1];
+ region.op(x, y, x + view.getWidth(), y + view.getHeight(), op);
+ }
+
@Override
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
insets = super.dispatchApplyWindowInsets(insets);
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 572e69b..feba7bb 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.Bundle;
import android.view.accessibility.AccessibilityEvent;
@@ -660,4 +661,17 @@
* @return true if the action was consumed by this ViewParent
*/
public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle arguments);
+
+ /**
+ * Given a touchable region of a child, this method reduces region by the bounds of all views on
+ * top of the child for which {@link View#canReceivePointerEvents} returns {@code true}. This
+ * applies recursively for all views in the view hierarchy on top of this one.
+ *
+ * @param touchableRegion The touchable region we want to modify.
+ * @param view A child view of this ViewGroup which indicates the z-order of the touchable
+ * region.
+ * @hide
+ */
+ default void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
+ }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2880e7f..49166ad 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1455,6 +1455,7 @@
@Override
public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) {
+ checkThread();
if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
mIsAnimating = true;
}
@@ -2811,8 +2812,7 @@
MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
.getMainContentCaptureSession();
for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) {
- String sessionId = mAttachInfo.mContentCaptureEvents
- .keyAt(i);
+ int sessionId = mAttachInfo.mContentCaptureEvents.keyAt(i);
mainSession.notifyViewTreeEvent(sessionId, /* started= */ true);
ArrayList<Object> events = mAttachInfo.mContentCaptureEvents
.valueAt(i);
@@ -2827,8 +2827,8 @@
Log.w(mTag, "no content capture session on view: " + view);
continue for_each_event;
}
- String actualId = session.getId().toString();
- if (!actualId.equals(sessionId)) {
+ int actualId = session.getId();
+ if (actualId != sessionId) {
Log.w(mTag, "content capture session mismatch for view (" + view
+ "): was " + sessionId + " before, it's " + actualId + " now");
continue for_each_event;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 385d491..774a359 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1682,17 +1682,29 @@
}
/**
- * Gets the node bounds in parent coordinates.
+ * Gets the node bounds in the viewParent's coordinates.
+ * {@link #getParent()} does not represent the source's viewParent.
+ * Instead it represents the result of {@link View#getParentForAccessibility()},
+ * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true.
+ * So this method is not reliable.
*
* @param outBounds The output node bounds.
+ * @deprecated Use {@link #getBoundsInScreen(Rect)} instead.
+ *
*/
+ @Deprecated
public void getBoundsInParent(Rect outBounds) {
outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
mBoundsInParent.right, mBoundsInParent.bottom);
}
/**
- * Sets the node bounds in parent coordinates.
+ * Sets the node bounds in the viewParent's coordinates.
+ * {@link #getParent()} does not represent the source's viewParent.
+ * Instead it represents the result of {@link View#getParentForAccessibility()},
+ * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true.
+ * So this method is not reliable.
+ *
* <p>
* <strong>Note:</strong> Cannot be called from an
* {@link android.accessibilityservice.AccessibilityService}.
@@ -1702,7 +1714,9 @@
* @param bounds The node bounds.
*
* @throws IllegalStateException If called from an AccessibilityService.
+ * @deprecated Accessibility services should not care about these bounds.
*/
+ @Deprecated
public void setBoundsInParent(Rect bounds) {
enforceNotSealed();
mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 77a0c4c..6503a80 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -2178,6 +2178,18 @@
boolean saveOnAllViewsInvisible, boolean saveOnFinish,
@Nullable AutofillId[] fillableIds, @Nullable AutofillId saveTriggerId) {
synchronized (mLock) {
+ if (sVerbose) {
+ Log.v(TAG, "setTrackedViews(): sessionId=" + sessionId
+ + ", trackedIds=" + Arrays.toString(trackedIds)
+ + ", saveOnAllViewsInvisible=" + saveOnAllViewsInvisible
+ + ", saveOnFinish=" + saveOnFinish
+ + ", fillableIds=" + Arrays.toString(fillableIds)
+ + ", saveTrigerId=" + saveTriggerId
+ + ", mFillableIds=" + mFillableIds
+ + ", mEnabled=" + mEnabled
+ + ", mSessionId=" + mSessionId);
+
+ }
if (mEnabled && mSessionId == sessionId) {
if (saveOnAllViewsInvisible) {
mTrackedViews = new TrackedViews(trackedIds);
@@ -2192,10 +2204,6 @@
for (AutofillId id : fillableIds) {
mFillableIds.add(id);
}
- if (sVerbose) {
- Log.v(TAG, "setTrackedViews(): fillableIds=" + Arrays.toString(fillableIds)
- + ", mFillableIds" + mFillableIds);
- }
}
if (mSaveTriggerId != null && !mSaveTriggerId.equals(saveTriggerId)) {
diff --git a/core/java/android/view/autofill/AutofillManagerInternal.java b/core/java/android/view/autofill/AutofillManagerInternal.java
index d5862bd..3de1a03 100644
--- a/core/java/android/view/autofill/AutofillManagerInternal.java
+++ b/core/java/android/view/autofill/AutofillManagerInternal.java
@@ -33,7 +33,10 @@
public abstract void onBackKeyPressed();
/**
- * Gets autofill options for a package
+ * Gets autofill options for a package.
+ *
+ * <p><b>NOTE: </b>this method is called by the {@code ActivityManager} service and hence cannot
+ * hold the main service lock.
*
* @param packageName The package for which to query.
* @param versionCode The package version code.
diff --git a/cmds/statsd/src/logd/LogListener.cpp b/core/java/android/view/contentcapture/ContentCaptureCondition.aidl
similarity index 60%
rename from cmds/statsd/src/logd/LogListener.cpp
rename to core/java/android/view/contentcapture/ContentCaptureCondition.aidl
index ddb26f9..99f8894 100644
--- a/cmds/statsd/src/logd/LogListener.cpp
+++ b/core/java/android/view/contentcapture/ContentCaptureCondition.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
+/**
+ * Copyright (c) 2019, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -14,18 +14,6 @@
* limitations under the License.
*/
-#include "logd/LogListener.h"
+package android.view.contentcapture;
-namespace android {
-namespace os {
-namespace statsd {
-
-LogListener::LogListener() {
-}
-
-LogListener::~LogListener() {
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
+parcelable ContentCaptureCondition;
diff --git a/core/java/android/view/contentcapture/ContentCaptureCondition.java b/core/java/android/view/contentcapture/ContentCaptureCondition.java
index ed87257..cf171d7 100644
--- a/core/java/android/view/contentcapture/ContentCaptureCondition.java
+++ b/core/java/android/view/contentcapture/ContentCaptureCondition.java
@@ -20,6 +20,7 @@
import android.content.LocusId;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.DebugUtils;
import com.android.internal.util.Preconditions;
@@ -58,7 +59,6 @@
public ContentCaptureCondition(@NonNull LocusId locusId, @Flags int flags) {
this.mLocusId = Preconditions.checkNotNull(locusId);
this.mFlags = flags;
- // TODO(b/129267994): check flags, add test case for null and invalid flags
}
/**
@@ -79,6 +79,42 @@
}
@Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mFlags;
+ result = prime * result + ((mLocusId == null) ? 0 : mLocusId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ final ContentCaptureCondition other = (ContentCaptureCondition) obj;
+ if (mFlags != other.mFlags) return false;
+ if (mLocusId == null) {
+ if (other.mLocusId != null) return false;
+ } else {
+ if (!mLocusId.equals(other.mLocusId)) return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder string = new StringBuilder(mLocusId.toString()); // LocusID is PII safe
+ if (mFlags != 0) {
+ string
+ .append(" (")
+ .append(DebugUtils.flagsToString(ContentCaptureCondition.class, "FLAG_", mFlags))
+ .append(')');
+ }
+ return string.toString();
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 5a27e94..94e548f 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -15,6 +15,8 @@
*/
package android.view.contentcapture;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -35,9 +37,9 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-
/**
- * Context associated with a {@link ContentCaptureSession}.
+ * Context associated with a {@link ContentCaptureSession} - see {@link ContentCaptureManager} for
+ * more info.
*/
public final class ContentCaptureContext implements Parcelable {
@@ -50,8 +52,7 @@
/**
* Flag used to indicate that the app explicitly disabled content capture for the activity
- * (using
- * {@link android.view.contentcapture.ContentCaptureManager#setContentCaptureEnabled(boolean)}),
+ * (using {@link ContentCaptureManager#setContentCaptureEnabled(boolean)}),
* in which case the service will just receive activity-level events.
*
* @hide
@@ -107,7 +108,7 @@
private final int mDisplayId;
// Fields below are set by the service upon "delivery" and are not marshalled in the parcel
- private @Nullable String mParentSessionId;
+ private int mParentSessionId = NO_SESSION_ID;
/** @hide */
public ContentCaptureContext(@Nullable ContentCaptureContext clientContext,
@@ -198,11 +199,12 @@
@SystemApi
@TestApi
public @Nullable ContentCaptureSessionId getParentSessionId() {
- return mParentSessionId == null ? null : new ContentCaptureSessionId(mParentSessionId);
+ return mParentSessionId == NO_SESSION_ID ? null
+ : new ContentCaptureSessionId(mParentSessionId);
}
/** @hide */
- public void setParentSessionId(@NonNull String parentSessionId) {
+ public void setParentSessionId(int parentSessionId) {
mParentSessionId = parentSessionId;
}
@@ -260,9 +262,10 @@
* <li>A unique identifier of the application state (for example, a conversation between
* 2 users in a chat app).
*
+ * <p>See {@link ContentCaptureManager} for more info about the content capture context.
+ *
* @param id id associated with this context.
*/
- // TODO(b/123577059): make sure this is well documented and understandable
public Builder(@NonNull LocusId id) {
mId = Preconditions.checkNotNull(id);
}
@@ -316,7 +319,7 @@
}
pw.print(", taskId="); pw.print(mTaskId);
pw.print(", displayId="); pw.print(mDisplayId);
- if (mParentSessionId != null) {
+ if (mParentSessionId != NO_SESSION_ID) {
pw.print(", parentId="); pw.print(mParentSessionId);
}
if (mFlags > 0) {
@@ -348,7 +351,7 @@
builder.append(", hasExtras");
}
}
- if (mParentSessionId != null) {
+ if (mParentSessionId != NO_SESSION_ID) {
builder.append(", parentId=").append(mParentSessionId);
}
return builder.append(']').toString();
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 8188e05..bd38629 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -16,6 +16,7 @@
package android.view.contentcapture;
import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -126,25 +127,25 @@
@Retention(RetentionPolicy.SOURCE)
public @interface EventType{}
- private final @NonNull String mSessionId;
+ private final int mSessionId;
private final int mType;
private final long mEventTime;
private @Nullable AutofillId mId;
private @Nullable ArrayList<AutofillId> mIds;
private @Nullable ViewNode mNode;
private @Nullable CharSequence mText;
- private @Nullable String mParentSessionId;
+ private int mParentSessionId = NO_SESSION_ID;
private @Nullable ContentCaptureContext mClientContext;
/** @hide */
- public ContentCaptureEvent(@NonNull String sessionId, int type, long eventTime) {
+ public ContentCaptureEvent(int sessionId, int type, long eventTime) {
mSessionId = sessionId;
mType = type;
mEventTime = eventTime;
}
/** @hide */
- public ContentCaptureEvent(@NonNull String sessionId, int type) {
+ public ContentCaptureEvent(int sessionId, int type) {
this(sessionId, type, System.currentTimeMillis());
}
@@ -185,7 +186,7 @@
*
* @hide
*/
- public ContentCaptureEvent setParentSessionId(@NonNull String parentSessionId) {
+ public ContentCaptureEvent setParentSessionId(int parentSessionId) {
mParentSessionId = parentSessionId;
return this;
}
@@ -202,7 +203,7 @@
/** @hide */
@NonNull
- public String getSessionId() {
+ public int getSessionId() {
return mSessionId;
}
@@ -212,7 +213,7 @@
* @hide
*/
@Nullable
- public String getParentSessionId() {
+ public int getParentSessionId() {
return mParentSessionId;
}
@@ -357,10 +358,10 @@
if (mNode != null) {
pw.print(", mNode.id="); pw.print(mNode.getAutofillId());
}
- if (mSessionId != null) {
+ if (mSessionId != NO_SESSION_ID) {
pw.print(", sessionId="); pw.print(mSessionId);
}
- if (mParentSessionId != null) {
+ if (mParentSessionId != NO_SESSION_ID) {
pw.print(", parentSessionId="); pw.print(mParentSessionId);
}
if (mText != null) {
@@ -377,7 +378,7 @@
final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=")
.append(getTypeAsString(mType));
string.append(", session=").append(mSessionId);
- if (mType == TYPE_SESSION_STARTED && mParentSessionId != null) {
+ if (mType == TYPE_SESSION_STARTED && mParentSessionId != NO_SESSION_ID) {
string.append(", parent=").append(mParentSessionId);
}
if (mId != null) {
@@ -409,7 +410,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeString(mSessionId);
+ parcel.writeInt(mSessionId);
parcel.writeInt(mType);
parcel.writeLong(mEventTime);
parcel.writeParcelable(mId, flags);
@@ -417,7 +418,7 @@
ViewNode.writeToParcel(parcel, mNode, flags);
parcel.writeCharSequence(mText);
if (mType == TYPE_SESSION_STARTED || mType == TYPE_SESSION_FINISHED) {
- parcel.writeString(mParentSessionId);
+ parcel.writeInt(mParentSessionId);
}
if (mType == TYPE_SESSION_STARTED || mType == TYPE_CONTEXT_UPDATED) {
parcel.writeParcelable(mClientContext, flags);
@@ -430,7 +431,7 @@
@Override
@NonNull
public ContentCaptureEvent createFromParcel(Parcel parcel) {
- final String sessionId = parcel.readString();
+ final int sessionId = parcel.readInt();
final int type = parcel.readInt();
final long eventTime = parcel.readLong();
final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type, eventTime);
@@ -448,7 +449,7 @@
}
event.setText(parcel.readCharSequence());
if (type == TYPE_SESSION_STARTED || type == TYPE_SESSION_FINISHED) {
- event.setParentSessionId(parcel.readString());
+ event.setParentSessionId(parcel.readInt());
}
if (type == TYPE_SESSION_STARTED || type == TYPE_CONTEXT_UPDATED) {
event.setClientContext(parcel.readParcelable(null));
diff --git a/core/java/android/view/contentcapture/ContentCaptureHelper.java b/core/java/android/view/contentcapture/ContentCaptureHelper.java
index 6bc3829..c7ca220 100644
--- a/core/java/android/view/contentcapture/ContentCaptureHelper.java
+++ b/core/java/android/view/contentcapture/ContentCaptureHelper.java
@@ -23,9 +23,14 @@
import android.annotation.Nullable;
import android.os.Build;
import android.provider.DeviceConfig;
+import android.util.ArraySet;
import android.util.Log;
import android.view.contentcapture.ContentCaptureManager.LoggingLevel;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
/**
* Helper class for this package and server's.
*
@@ -101,6 +106,22 @@
}
}
+ /**
+ * Converts a set to a list.
+ */
+ @Nullable
+ public static <T> ArrayList<T> toList(@Nullable Set<T> set) {
+ return set == null ? null : new ArrayList<T>(set);
+ }
+
+ /**
+ * Converts a list to a set.
+ */
+ @Nullable
+ public static <T> ArraySet<T> toSet(@Nullable List<T> list) {
+ return list == null ? null : new ArraySet<T>(list);
+ }
+
private ContentCaptureHelper() {
throw new UnsupportedOperationException("contains only static methods");
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 817b130..2539356 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -17,6 +17,7 @@
import static android.view.contentcapture.ContentCaptureHelper.sDebug;
import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
+import static android.view.contentcapture.ContentCaptureHelper.toSet;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -28,12 +29,15 @@
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.Context;
+import android.graphics.Canvas;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import android.view.View;
+import android.view.ViewStructure;
import android.view.contentcapture.ContentCaptureSession.FlushReason;
import com.android.internal.annotations.GuardedBy;
@@ -43,10 +47,152 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Set;
/**
- * TODO(b/123577059): add javadocs / mention it can be null
+ * <p>The {@link ContentCaptureManager} provides additional ways for for apps to
+ * integrate with the content capture subsystem.
+ *
+ * <p>Content capture provides real-time, continuous capture of application activity, display and
+ * events to an intelligence service that is provided by the Android system. The intelligence
+ * service then uses that info to mediate and speed user journey through different apps. For
+ * example, when the user receives a restaurant address in a chat app and switchs to a map app
+ * to search for that restaurant, the intelligence service could offer an autofill dialog to
+ * let the user automatically select its address.
+ *
+ * <p>Content capture was designed with two major concerns in mind: privacy and performance.
+ *
+ * <ul>
+ * <li><b>Privacy:</b> the intelligence service is a trusted component provided that is provided
+ * by the device manufacturer and that cannot be changed by the user (although the user can
+ * globaly disable content capture using the Android Settings app). This service can only use the
+ * data for in-device machine learning, which is enforced both by process isolation and
+ * <a href="https://source.android.com/compatibility/cdd">CDD requirements</a>.
+ * <li><b>Performance:</b> content capture is highly optimized to minimize its impact in the app
+ * jankiness and overall device system health. For example, its only enabled on apps (or even
+ * specific activities from an app) that were explicitly whitelisted by the intelligence service,
+ * and it buffers the events so they are sent in a batch to the service (see
+ * {@link #isContentCaptureEnabled()} for other cases when its disabled).
+ * </ul>
+ *
+ * <p>In fact, before using this manager, the app developer should check if it's available. Example:
+ * <code>
+ * ContentCaptureManager mgr = context.getSystemService(ContentCaptureManager.class);
+ * if (mgr != null && mgr.isContentCaptureEnabled()) {
+ * // ...
+ * }
+ * </code>
+ *
+ * <p>App developers usually don't need to explicitly interact with content capture, except when the
+ * app:
+ *
+ * <ul>
+ * <li>Can define a contextual {@link android.content.LocusId} to identify unique state (such as a
+ * conversation between 2 chat users).
+ * <li>Can have multiple view hierarchies with different contextual meaning (for example, a
+ * browser app with multiple tabs, each representing a different URL).
+ * <li>Contains custom views (that extend View directly and are not provided by the standard
+ * Android SDK.
+ * <li>Contains views that provide their own virtual hierarchy (like a web browser that render the
+ * HTML elements using a Canvas).
+ * </ul>
+ *
+ * <p>The main integration point with content capture is the {@link ContentCaptureSession}. A "main"
+ * session is automatically created by the Android System when content capture is enabled for the
+ * activity and its used by the standard Android views to notify the content capture service of
+ * events such as views being added, views been removed, and text changed by user input. The session
+ * could have a {@link ContentCaptureContext} to provide more contextual info about it, such as
+ * the locus associated with the view hierarchy (see {@link android.content.LocusId} for more info
+ * about locus). By default, the main session doesn't have a {@code ContentCaptureContext}, but you
+ * can change it after its created. Example:
+ *
+ * <pre><code>
+ * protected void onCreate(Bundle savedInstanceState) {
+ * // Initialize view structure
+ * ContentCaptureSession session = rootView.getContentCaptureSession();
+ * if (session != null) {
+ * session.setContentCaptureContext(ContentCaptureContext.forLocusId("chat_UserA_UserB"));
+ * }
+ * }
+ * </code></pre>
+ *
+ * <p>If your activity contains view hierarchies with a different contextual meaning, you should
+ * created child sessions for each view hierarchy root. For example, if your activity is a browser,
+ * you could use the main session for the main URL being rendered, then child sessions for each
+ * {@code IFRAME}:
+ *
+ * <pre><code>
+ * ContentCaptureSession mMainSession;
+ *
+ * protected void onCreate(Bundle savedInstanceState) {
+ * // Initialize view structure...
+ * mMainSession = rootView.getContentCaptureSession();
+ * if (mMainSession != null) {
+ * mMainSession.setContentCaptureContext(
+ * ContentCaptureContext.forLocusId("https://example.com"));
+ * }
+ * }
+ *
+ * private void loadIFrame(View iframeRootView, String url) {
+ * if (mMainSession != null) {
+ * ContentCaptureSession iFrameSession = mMainSession.newChild(
+ * ContentCaptureContext.forLocusId(url));
+ * }
+ * iframeRootView.setContentCaptureSession(iFrameSession);
+ * }
+ * // Load iframe...
+ * }
+ * </code></pre>
+ *
+ * <p>If your activity has custom views (i.e., views that extend {@link View} directly and provide
+ * just one logical view, not a virtual tree hiearchy) and it provides content that's relevant for
+ * content capture (as of {@link android.os.Build.VERSION_CODES#Q Android Q}, the only relevant
+ * content is text), then your view implementation should:
+ *
+ * <ul>
+ * <li>Set it as important for content capture.
+ * <li>Fill {@link ViewStructure} used for content capture.
+ * <li>Notify the {@link ContentCaptureSession} when the text is changed by user input.
+ * </ul>
+ *
+ * <p>Here's an example of the relevant methods for an {@code EditText}-like view:
+ *
+ * <pre><code>
+ * public class MyEditText extends View {
+ *
+ * public MyEditText(...) {
+ * if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) {
+ * setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES);
+ * }
+ * }
+ *
+ * public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) {
+ * super.onProvideContentCaptureStructure(structure, flags);
+ *
+ * structure.setText(getText(), getSelectionStart(), getSelectionEnd());
+ * structure.setHint(getHint());
+ * structure.setInputType(getInputType());
+ * // set other properties like setTextIdEntry(), setTextLines(), setTextStyle(),
+ * // setMinTextEms(), setMaxTextEms(), setMaxTextLength()
+ * }
+ *
+ * private void onTextChanged() {
+ * if (isLaidOut() && isImportantForContentCapture() && isTextEditable()) {
+ * ContentCaptureManager mgr = mContext.getSystemService(ContentCaptureManager.class);
+ * if (cm != null && cm.isContentCaptureEnabled()) {
+ * ContentCaptureSession session = getContentCaptureSession();
+ * if (session != null) {
+ * session.notifyViewTextChanged(getAutofillId(), getText());
+ * }
+ * }
+ * }
+ * </code></pre>
+ *
+ * <p>If your view provides its own virtual hierarchy (for example, if it's a browser that draws
+ * the HTML using {@link Canvas} or native libraries in a different render process), then the view
+ * is also responsible to notify the session when the virtual elements appear and disappear - see
+ * {@link View#onProvideContentCaptureStructure(ViewStructure, int)} for more info.
*/
@SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE)
public final class ContentCaptureManager {
@@ -69,7 +215,7 @@
/**
* DeviceConfig property used by {@code com.android.server.SystemServer} on start to decide
- * whether the Content Capture service should be created or not
+ * whether the content capture service should be created or not
*
* <p>By default it should *NOT* be set (or set to {@code "default"}, so the decision is based
* on whether the OEM provides an implementation for the service), but it can be overridden to:
@@ -340,12 +486,12 @@
* <p>There are many reasons it could be disabled, such as:
* <ul>
* <li>App itself disabled content capture through {@link #setContentCaptureEnabled(boolean)}.
- * <li>Service disabled content capture for this specific activity.
- * <li>Service disabled content capture for all activities of this package.
- * <li>Service disabled content capture globally.
- * <li>User disabled content capture globally (through Settings).
- * <li>OEM disabled content capture globally.
- * <li>Transient errors.
+ * <li>Intelligence service did not whitelist content capture for this activity's package.
+ * <li>Intelligence service did not whitelist content capture for this specific activity.
+ * <li>Intelligence service disabled content capture globally.
+ * <li>User disabled content capture globally through the Android Settings app.
+ * <li>Device manufacturer (OEM) disabled content capture globally.
+ * <li>Transient errors, such as intelligence service package being updated.
* </ul>
*/
public boolean isContentCaptureEnabled() {
@@ -369,11 +515,22 @@
* capture events for websites the content capture service is not interested on.
*
* @return list of conditions, or {@code null} if the service didn't set any restriction
- * (in which case content capture events should always be generated).
+ * (in which case content capture events should always be generated). If the list is empty,
+ * then it should not generate any event at all.
*/
@Nullable
public Set<ContentCaptureCondition> getContentCaptureConditions() {
- return null; // TODO(b/129267994): implement
+ // NOTE: we could cache the conditions on ContentCaptureOptions, but then it would be stick
+ // to the lifetime of the app. OTOH, by dynamically calling the server every time, we allow
+ // the service to fine tune how long-lived apps (like browsers) are whitelisted.
+ if (!isContentCaptureEnabled() && !mOptions.lite) return null;
+
+ final SyncResultReceiver resultReceiver = syncRun(
+ (r) -> mService.getContentCaptureConditions(mContext.getPackageName(), r));
+
+ final ArrayList<ContentCaptureCondition> result = resultReceiver
+ .getParcelableListResult();
+ return toSet(result);
}
/**
@@ -393,12 +550,12 @@
}
/**
- * Gets whether Content Capture is enabled for the given user.
+ * Gets whether content capture is enabled for the given user.
*
- * <p>This method is typically used by the Content Capture Service settings page, so it can
+ * <p>This method is typically used by the content capture service settings page, so it can
* provide a toggle to enable / disable it.
*
- * @throws SecurityException if caller is not the app that owns the Content Capture service
+ * @throws SecurityException if caller is not the app that owns the content capture service
* associated with the user.
*
* @hide
@@ -406,21 +563,14 @@
@SystemApi
@TestApi
public boolean isContentCaptureFeatureEnabled() {
- final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
- final int resultCode;
- try {
- mService.isContentCaptureFeatureEnabled(resultReceiver);
- resultCode = resultReceiver.getIntResult();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ final SyncResultReceiver resultReceiver = syncRun(
+ (r) -> mService.isContentCaptureFeatureEnabled(r));
+ final int resultCode = resultReceiver.getIntResult();
switch (resultCode) {
case RESULT_CODE_TRUE:
return true;
case RESULT_CODE_FALSE:
return false;
- case RESULT_CODE_SECURITY_EXCEPTION:
- throw new SecurityException("caller is not user's ContentCapture service");
default:
Log.wtf(TAG, "received invalid result: " + resultCode);
return false;
@@ -428,7 +578,7 @@
}
/**
- * Called by the app to request the Content Capture service to remove user-data associated with
+ * Called by the app to request the content capture service to remove user-data associated with
* some context.
*
* @param request object specifying what user data should be removed.
@@ -443,6 +593,26 @@
}
}
+ /**
+ * Runs a sync method in the service, properly handling exceptions.
+ *
+ * @throws SecurityException if caller is not allowed to execute the method.
+ */
+ @NonNull
+ private SyncResultReceiver syncRun(@NonNull MyRunnable r) {
+ final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+ try {
+ r.run(resultReceiver);
+ final int resultCode = resultReceiver.getIntResult();
+ if (resultCode == RESULT_CODE_SECURITY_EXCEPTION) {
+ throw new SecurityException(resultReceiver.getStringResult());
+ }
+ return resultReceiver;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @hide */
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.println("ContentCaptureManager");
@@ -466,4 +636,8 @@
}
}
}
+
+ private interface MyRunnable {
+ void run(@NonNull SyncResultReceiver receiver) throws RemoteException;
+ }
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index ed1ca2a..7761038 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -38,7 +38,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.UUID;
+import java.util.Random;
/**
* Session used to notify a system-provided Content Capture service about events associated with
@@ -48,6 +48,11 @@
private static final String TAG = ContentCaptureSession.class.getSimpleName();
+ private static final Random sIdGenerator = new Random();
+
+ /** @hide */
+ public static final int NO_SESSION_ID = 0;
+
/**
* Initial state, when there is no session.
*
@@ -186,7 +191,7 @@
/** @hide */
@Nullable
- protected final String mId;
+ protected final int mId;
private int mState = UNKNOWN_STATE;
@@ -210,13 +215,14 @@
/** @hide */
protected ContentCaptureSession() {
- this(UUID.randomUUID().toString());
+ this(getRandomSessionId());
}
/** @hide */
@VisibleForTesting
- public ContentCaptureSession(@NonNull String id) {
- mId = Preconditions.checkNotNull(id);
+ public ContentCaptureSession(int id) {
+ Preconditions.checkArgument(id != NO_SESSION_ID);
+ mId = id;
}
// Used by ChildCOntentCaptureSession
@@ -241,15 +247,8 @@
}
/** @hide */
- @VisibleForTesting
- public int getIdAsInt() {
- // TODO(b/121197119): use sessionId instead of hashcode once it's changed to int
- return mId.hashCode();
- }
-
- /** @hide */
@NonNull
- public String getId() {
+ public int getId() {
return mId;
}
@@ -415,7 +414,7 @@
// TODO(b/123036895): use a internalNotifyViewsDisappeared that optimizes how the event is
// parcelized
for (long id : virtualIds) {
- internalNotifyViewDisappeared(new AutofillId(hostId, id, getIdAsInt()));
+ internalNotifyViewDisappeared(new AutofillId(hostId, id, mId));
}
}
@@ -464,7 +463,7 @@
public @NonNull AutofillId newAutofillId(@NonNull AutofillId hostId, long virtualChildId) {
Preconditions.checkNotNull(hostId);
Preconditions.checkArgument(hostId.isNonVirtual(), "hostId cannot be virtual: %s", hostId);
- return new AutofillId(hostId, virtualChildId, getIdAsInt());
+ return new AutofillId(hostId, virtualChildId, mId);
}
/**
@@ -480,7 +479,7 @@
@NonNull
public final ViewStructure newVirtualViewStructure(@NonNull AutofillId parentId,
long virtualId) {
- return new ViewNode.ViewStructureImpl(parentId, virtualId, getIdAsInt());
+ return new ViewNode.ViewStructureImpl(parentId, virtualId, mId);
}
boolean isContentCaptureEnabled() {
@@ -511,7 +510,7 @@
@Override
public String toString() {
- return mId;
+ return Integer.toString(mId);
}
/** @hide */
@@ -541,4 +540,12 @@
return "UNKOWN-" + reason;
}
}
+
+ private static int getRandomSessionId() {
+ int id;
+ do {
+ id = sIdGenerator.nextInt();
+ } while (id == NO_SESSION_ID);
+ return id;
+ }
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureSessionId.java b/core/java/android/view/contentcapture/ContentCaptureSessionId.java
index e7c350a..2d350b2 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSessionId.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSessionId.java
@@ -27,7 +27,7 @@
*/
public final class ContentCaptureSessionId implements Parcelable {
- private final @NonNull String mValue;
+ private final @NonNull int mValue;
/**
* Creates a new instance.
@@ -36,14 +36,14 @@
*
* @hide
*/
- public ContentCaptureSessionId(@NonNull String value) {
+ public ContentCaptureSessionId(@NonNull int value) {
mValue = value;
}
/**
* @hide
*/
- public String getValue() {
+ public int getValue() {
return mValue;
}
@@ -51,7 +51,7 @@
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((mValue == null) ? 0 : mValue.hashCode());
+ result = prime * result + mValue;
return result;
}
@@ -61,11 +61,7 @@
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final ContentCaptureSessionId other = (ContentCaptureSessionId) obj;
- if (mValue == null) {
- if (other.mValue != null) return false;
- } else if (!mValue.equals(other.mValue)) {
- return false;
- }
+ if (mValue != other.mValue) return false;
return true;
}
@@ -77,9 +73,10 @@
*/
@Override
public String toString() {
- return mValue;
+ return Integer.toString(mValue);
}
+
/** @hide */
// TODO(b/111276913): dump to proto as well
public void dump(PrintWriter pw) {
@@ -93,16 +90,16 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeString(mValue);
+ parcel.writeInt(mValue);
}
- public static final @android.annotation.NonNull Parcelable.Creator<ContentCaptureSessionId> CREATOR =
+ public static final @NonNull Parcelable.Creator<ContentCaptureSessionId> CREATOR =
new Parcelable.Creator<ContentCaptureSessionId>() {
@Override
@NonNull
public ContentCaptureSessionId createFromParcel(Parcel parcel) {
- return new ContentCaptureSessionId(parcel.readString());
+ return new ContentCaptureSessionId(parcel.readInt());
}
@Override
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 15fbaa2..7335073 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -42,13 +42,13 @@
* {@link IContentCaptureContext#flags}).
*/
void startSession(IBinder activityToken, in ComponentName componentName,
- String sessionId, int flags, in IResultReceiver result);
+ int sessionId, int flags, in IResultReceiver result);
/**
* Marks the end of a session for the calling user identified by
* the corresponding {@code startSession}'s {@code sessionId}.
*/
- void finishSession(String sessionId);
+ void finishSession(int sessionId);
/**
* Returns the content capture service's component name (if enabled and
@@ -72,4 +72,9 @@
* Returns a ComponentName with the name of custom service activity, if defined.
*/
void getServiceSettingsActivity(in IResultReceiver result);
+
+ /**
+ * Returns a list with the ContentCaptureConditions for the package (or null if not defined).
+ */
+ void getContentCaptureConditions(String packageName, in IResultReceiver result);
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 790b8f9..784cf9c 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -318,7 +318,7 @@
if (!mEvents.isEmpty() && eventType == TYPE_VIEW_DISAPPEARED) {
final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
if (lastEvent.getType() == TYPE_VIEW_DISAPPEARED
- && event.getSessionId().equals(lastEvent.getSessionId())) {
+ && event.getSessionId() == lastEvent.getSessionId()) {
if (sVerbose) {
Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session "
+ lastEvent.getSessionId());
@@ -581,37 +581,35 @@
// TODO(b/122454205): refactor "notifyXXXX" methods below to a common "Buffer" object that is
// shared between ActivityContentCaptureSession and ChildContentCaptureSession objects. Such
// change should also get get rid of the "internalNotifyXXXX" methods above
- void notifyChildSessionStarted(@NonNull String parentSessionId,
- @NonNull String childSessionId, @NonNull ContentCaptureContext clientContext) {
+ void notifyChildSessionStarted(int parentSessionId, int childSessionId,
+ @NonNull ContentCaptureContext clientContext) {
sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
.setParentSessionId(parentSessionId).setClientContext(clientContext),
FORCE_FLUSH);
}
- void notifyChildSessionFinished(@NonNull String parentSessionId,
- @NonNull String childSessionId) {
+ void notifyChildSessionFinished(int parentSessionId, int childSessionId) {
sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
.setParentSessionId(parentSessionId), FORCE_FLUSH);
}
- void notifyViewAppeared(@NonNull String sessionId, @NonNull ViewStructureImpl node) {
+ void notifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) {
sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
.setViewNode(node.mNode));
}
/** Public because is also used by ViewRootImpl */
- public void notifyViewDisappeared(@NonNull String sessionId, @NonNull AutofillId id) {
+ public void notifyViewDisappeared(int sessionId, @NonNull AutofillId id) {
sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id));
}
- void notifyViewTextChanged(@NonNull String sessionId, @NonNull AutofillId id,
- @Nullable CharSequence text) {
+ void notifyViewTextChanged(int sessionId, @NonNull AutofillId id, @Nullable CharSequence text) {
sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED).setAutofillId(id)
.setText(text));
}
/** Public because is also used by ViewRootImpl */
- public void notifyViewTreeEvent(@NonNull String sessionId, boolean started) {
+ public void notifyViewTreeEvent(int sessionId, boolean started) {
final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED;
sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH);
}
@@ -622,8 +620,7 @@
sendEvent(new ContentCaptureEvent(mId, type), FORCE_FLUSH);
}
- void notifyContextUpdated(@NonNull String sessionId,
- @Nullable ContentCaptureContext context) {
+ void notifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) {
sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
.setClientContext(context));
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a5a1a80c..a961783 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10081,7 +10081,7 @@
}
/**
- * Return true iff there is a selection inside this text view.
+ * Return true iff there is a selection of nonzero length inside this text view.
*/
public boolean hasSelection() {
final int selectionStart = getSelectionStart();
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index f29174b..f14b50d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1594,7 +1594,7 @@
if (info == null) return null;
// Now fetch app icon and raster with no badging even in work profile
- Bitmap appIcon = (new ActivityInfoPresentationGetter(info)).getIconBitmap();
+ Bitmap appIcon = makePresentationGetter(info).getIconBitmap();
// Raster target drawable with appIcon as a badge
SimpleIconFactory sif = SimpleIconFactory.obtain(ChooserActivity.this);
@@ -1865,8 +1865,9 @@
ri.noResourceId = true;
ri.icon = 0;
}
+ ResolveInfoPresentationGetter getter = makePresentationGetter(ri);
mCallerTargets.add(new DisplayResolveInfo(ii, ri,
- ri.loadLabel(pm), null, ii));
+ getter.getLabel(), getter.getSubLabel(), ii));
}
}
}
@@ -1879,12 +1880,6 @@
}
@Override
- public boolean showsExtendedInfo(TargetInfo info) {
- // We have badges so we don't need this text shown.
- return false;
- }
-
- @Override
public View onCreateView(ViewGroup parent) {
return mInflater.inflate(
com.android.internal.R.layout.resolve_grid_item, parent, false);
@@ -2301,8 +2296,10 @@
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
int columnCount = holder.getColumnCount();
+ final boolean isDirectShare = holder instanceof DirectShareViewHolder;
+
for (int i = 0; i < columnCount; i++) {
- final View v = mChooserListAdapter.createView(holder.getRow(i));
+ final View v = mChooserListAdapter.createView(holder.getRowByIndex(i));
final int column = i;
v.setOnClickListener(new OnClickListener() {
@Override
@@ -2321,27 +2318,31 @@
});
ViewGroup row = holder.addView(i, v);
- // Force height to be a given so we don't have visual disruption during scaling.
- LayoutParams lp = v.getLayoutParams();
- v.measure(spec, spec);
- if (lp == null) {
- lp = new LayoutParams(LayoutParams.MATCH_PARENT, v.getMeasuredHeight());
- row.setLayoutParams(lp);
- } else {
- lp.height = v.getMeasuredHeight();
+ // Force Direct Share to be 2 lines and auto-wrap to second line via hoz scroll =
+ // false. TextView#setHorizontallyScrolling must be reset after #setLines. Must be
+ // done before measuring.
+ if (isDirectShare) {
+ final ViewHolder vh = (ViewHolder) v.getTag();
+ vh.text.setLines(2);
+ vh.text.setHorizontallyScrolling(false);
+ vh.text2.setVisibility(View.GONE);
}
+
+ // Force height to be a given so we don't have visual disruption during scaling.
+ v.measure(spec, spec);
+ setViewHeight(v, v.getMeasuredHeight());
}
final ViewGroup viewGroup = holder.getViewGroup();
- // Pre-measure so we can scale later.
+ // Pre-measure and fix height so we can scale later.
holder.measure();
- LayoutParams lp = viewGroup.getLayoutParams();
- if (lp == null) {
- lp = new LayoutParams(LayoutParams.MATCH_PARENT, holder.getMeasuredRowHeight());
- viewGroup.setLayoutParams(lp);
- } else {
- lp.height = holder.getMeasuredRowHeight();
+ setViewHeight(viewGroup, holder.getMeasuredRowHeight());
+
+ if (isDirectShare) {
+ DirectShareViewHolder dsvh = (DirectShareViewHolder) holder;
+ setViewHeight(dsvh.getRow(0), holder.getMeasuredRowHeight());
+ setViewHeight(dsvh.getRow(1), holder.getMeasuredRowHeight());
}
viewGroup.setTag(holder);
@@ -2349,6 +2350,16 @@
return holder;
}
+ private void setViewHeight(View view, int heightPx) {
+ LayoutParams lp = view.getLayoutParams();
+ if (lp == null) {
+ lp = new LayoutParams(LayoutParams.MATCH_PARENT, heightPx);
+ view.setLayoutParams(lp);
+ } else {
+ lp.height = heightPx;
+ }
+ }
+
RowViewHolder createViewHolder(int viewType, ViewGroup parent) {
if (viewType == VIEW_TYPE_DIRECT_SHARE) {
ViewGroup parentGroup = (ViewGroup) mLayoutInflater.inflate(
@@ -2386,7 +2397,7 @@
if (startType != lastStartType || rowPosition == getContentPreviewRowCount()) {
row.setBackground(mChooserRowLayer);
- setVertPadding(row, mChooserRowServiceSpacing, 0);
+ setVertPadding(row, 0, 0);
} else {
row.setBackground(null);
setVertPadding(row, 0, 0);
@@ -2483,7 +2494,9 @@
abstract ViewGroup getViewGroup();
- abstract ViewGroup getRow(int index);
+ abstract ViewGroup getRowByIndex(int index);
+
+ abstract ViewGroup getRow(int rowNumber);
abstract void setViewVisibility(int i, int visibility);
@@ -2532,10 +2545,15 @@
return mRow;
}
- public ViewGroup getRow(int index) {
+ public ViewGroup getRowByIndex(int index) {
return mRow;
}
+ public ViewGroup getRow(int rowNumber) {
+ if (rowNumber == 0) return mRow;
+ return null;
+ }
+
public ViewGroup addView(int index, View v) {
mRow.addView(v);
mCells[index] = v;
@@ -2574,7 +2592,7 @@
}
public ViewGroup addView(int index, View v) {
- ViewGroup row = getRow(index);
+ ViewGroup row = getRowByIndex(index);
row.addView(v);
mCells[index] = v;
@@ -2589,10 +2607,14 @@
return mParent;
}
- public ViewGroup getRow(int index) {
+ public ViewGroup getRowByIndex(int index) {
return mRows.get(index / mCellCountPerRow);
}
+ public ViewGroup getRow(int rowNumber) {
+ return mRows.get(rowNumber);
+ }
+
public void measure() {
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
getRow(0).measure(spec, spec);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 84a1bed..9f9e083 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -83,7 +83,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@@ -499,33 +498,40 @@
/**
- * Loads the icon for the provided ApplicationInfo. Defaults to using the application icon over
- * any IntentFilter or Activity icon to increase user understanding, with an exception for
- * applications that hold the right permission. Always attempts to use icon resources over
- * PackageManager loading mechanisms so badging can be done by iconloader.
+ * Loads the icon and label for the provided ApplicationInfo. Defaults to using the application
+ * icon and label over any IntentFilter or Activity icon to increase user understanding, with an
+ * exception for applications that hold the right permission. Always attempts to use available
+ * resources over PackageManager loading mechanisms so badging can be done by iconloader. Uses
+ * Strings to strip creative formatting.
*/
- private abstract class TargetPresentationGetter {
- @Nullable abstract Drawable getIconSubstitute();
- @Nullable abstract String getAppSubLabel();
+ private abstract static class TargetPresentationGetter {
+ @Nullable abstract Drawable getIconSubstituteInternal();
+ @Nullable abstract String getAppSubLabelInternal();
+ private Context mCtx;
+ protected PackageManager mPm;
private final ApplicationInfo mAi;
+ private final int mIconDpi;
private final boolean mHasSubstitutePermission;
- TargetPresentationGetter(ApplicationInfo ai) {
+ TargetPresentationGetter(Context ctx, int iconDpi, ApplicationInfo ai) {
+ mCtx = ctx;
+ mPm = ctx.getPackageManager();
mAi = ai;
+ mIconDpi = iconDpi;
mHasSubstitutePermission = PackageManager.PERMISSION_GRANTED == mPm.checkPermission(
android.Manifest.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON,
mAi.packageName);
}
- Drawable getIcon() {
- return new BitmapDrawable(getResources(), getIconBitmap());
+ public Drawable getIcon() {
+ return new BitmapDrawable(mCtx.getResources(), getIconBitmap());
}
- Bitmap getIconBitmap() {
+ public Bitmap getIconBitmap() {
Drawable dr = null;
if (mHasSubstitutePermission) {
- dr = getIconSubstitute();
+ dr = getIconSubstituteInternal();
}
if (dr == null) {
@@ -542,18 +548,18 @@
dr = mAi.loadIcon(mPm);
}
- SimpleIconFactory sif = SimpleIconFactory.obtain(ResolverActivity.this);
+ SimpleIconFactory sif = SimpleIconFactory.obtain(mCtx);
Bitmap icon = sif.createUserBadgedIconBitmap(dr, Process.myUserHandle());
sif.recycle();
return icon;
}
- String getLabel() {
+ public String getLabel() {
String label = null;
// Apps with the substitute permission will always show the sublabel as their label
if (mHasSubstitutePermission) {
- label = getAppSubLabel();
+ label = getAppSubLabelInternal();
}
if (label == null) {
@@ -563,10 +569,14 @@
return label;
}
- String getSubLabel() {
+ public String getSubLabel() {
// Apps with the substitute permission will never have a sublabel
if (mHasSubstitutePermission) return null;
- return getAppSubLabel();
+ return getAppSubLabelInternal();
+ }
+
+ protected String loadLabelFromResource(Resources res, int resId) {
+ return res.getString(resId);
}
@Nullable
@@ -576,17 +586,19 @@
}
- protected class ResolveInfoPresentationGetter extends TargetPresentationGetter {
-
+ /**
+ * Loads the icon and label for the provided ResolveInfo.
+ */
+ @VisibleForTesting
+ public static class ResolveInfoPresentationGetter extends TargetPresentationGetter {
private final ResolveInfo mRi;
-
- ResolveInfoPresentationGetter(ResolveInfo ri) {
- super(ri.activityInfo.applicationInfo);
+ public ResolveInfoPresentationGetter(Context ctx, int iconDpi, ResolveInfo ri) {
+ super(ctx, iconDpi, ri.activityInfo.applicationInfo);
mRi = ri;
}
@Override
- Drawable getIconSubstitute() {
+ Drawable getIconSubstituteInternal() {
Drawable dr = null;
try {
// Do not use ResolveInfo#getIconResource() as it defaults to the app
@@ -603,20 +615,31 @@
}
@Override
- String getAppSubLabel() {
+ String getAppSubLabelInternal() {
+ // Will default to app name if no intent filter or activity label set, make sure to
+ // check if subLabel matches label before final display
return (String) mRi.loadLabel(mPm);
}
}
- protected class ActivityInfoPresentationGetter extends TargetPresentationGetter {
+ ResolveInfoPresentationGetter makePresentationGetter(ResolveInfo ri) {
+ return new ResolveInfoPresentationGetter(this, mIconDpi, ri);
+ }
+
+ /**
+ * Loads the icon and label for the provided ActivityInfo.
+ */
+ @VisibleForTesting
+ public static class ActivityInfoPresentationGetter extends TargetPresentationGetter {
private final ActivityInfo mActivityInfo;
- protected ActivityInfoPresentationGetter(ActivityInfo activityInfo) {
- super(activityInfo.applicationInfo);
+ public ActivityInfoPresentationGetter(Context ctx, int iconDpi,
+ ActivityInfo activityInfo) {
+ super(ctx, iconDpi, activityInfo.applicationInfo);
mActivityInfo = activityInfo;
}
@Override
- Drawable getIconSubstitute() {
+ Drawable getIconSubstituteInternal() {
Drawable dr = null;
try {
// Do not use ActivityInfo#getIconResource() as it defaults to the app
@@ -634,13 +657,19 @@
}
@Override
- String getAppSubLabel() {
+ String getAppSubLabelInternal() {
+ // Will default to app name if no activity label set, make sure to check if subLabel
+ // matches label before final display
return (String) mActivityInfo.loadLabel(mPm);
}
}
+ protected ActivityInfoPresentationGetter makePresentationGetter(ActivityInfo ai) {
+ return new ActivityInfoPresentationGetter(this, mIconDpi, ai);
+ }
+
Drawable loadIconForResolveInfo(ResolveInfo ri) {
- return (new ResolveInfoPresentationGetter(ri)).getIcon();
+ return makePresentationGetter(ri).getIcon();
}
@Override
@@ -1713,34 +1742,13 @@
}
}
- // Check for applications with same name and use application name or
- // package name if necessary
- ResolvedComponentInfo rci0 = sortedComponents.get(0);
- ResolveInfo r0 = rci0.getResolveInfoAt(0);
- int start = 0;
- CharSequence r0Label = r0.loadLabel(mPm);
- mHasExtendedInfo = false;
- for (int i = 1; i < N; i++) {
- if (r0Label == null) {
- r0Label = r0.activityInfo.packageName;
+ for (ResolvedComponentInfo rci : sortedComponents) {
+ final ResolveInfo ri = rci.getResolveInfoAt(0);
+ if (ri != null) {
+ ResolveInfoPresentationGetter pg = makePresentationGetter(ri);
+ addResolveInfoWithAlternates(rci, pg.getSubLabel(), pg.getLabel());
}
- ResolvedComponentInfo rci = sortedComponents.get(i);
- ResolveInfo ri = rci.getResolveInfoAt(0);
- CharSequence riLabel = ri.loadLabel(mPm);
- if (riLabel == null) {
- riLabel = ri.activityInfo.packageName;
- }
- if (riLabel.equals(r0Label)) {
- continue;
- }
- processGroup(sortedComponents, start, (i - 1), rci0, r0Label);
- rci0 = rci;
- r0 = ri;
- r0Label = riLabel;
- start = i;
}
- // Process last group
- processGroup(sortedComponents, start, (N - 1), rci0, r0Label);
}
postListReadyRunnable();
@@ -1782,55 +1790,6 @@
return mFilterLastUsed;
}
- private void processGroup(List<ResolvedComponentInfo> rList, int start, int end,
- ResolvedComponentInfo ro, CharSequence roLabel) {
- // Process labels from start to i
- int num = end - start+1;
- if (num == 1) {
- // No duplicate labels. Use label for entry at start
- addResolveInfoWithAlternates(ro, null, roLabel);
- } else {
- mHasExtendedInfo = true;
- boolean usePkg = false;
- final ApplicationInfo ai = ro.getResolveInfoAt(0).activityInfo.applicationInfo;
- final CharSequence startApp = ai.loadLabel(mPm);
- if (startApp == null) {
- usePkg = true;
- }
- if (!usePkg) {
- // Use HashSet to track duplicates
- HashSet<CharSequence> duplicates =
- new HashSet<CharSequence>();
- duplicates.add(startApp);
- for (int j = start+1; j <= end ; j++) {
- ResolveInfo jRi = rList.get(j).getResolveInfoAt(0);
- CharSequence jApp = jRi.activityInfo.applicationInfo.loadLabel(mPm);
- if ( (jApp == null) || (duplicates.contains(jApp))) {
- usePkg = true;
- break;
- } else {
- duplicates.add(jApp);
- }
- }
- // Clear HashSet for later use
- duplicates.clear();
- }
- for (int k = start; k <= end; k++) {
- final ResolvedComponentInfo rci = rList.get(k);
- final ResolveInfo add = rci.getResolveInfoAt(0);
- final CharSequence extraInfo;
- if (usePkg) {
- // Use package name for all entries from start to end-1
- extraInfo = add.activityInfo.packageName;
- } else {
- // Use application name for all entries from start to end-1
- extraInfo = add.activityInfo.applicationInfo.loadLabel(mPm);
- }
- addResolveInfoWithAlternates(rci, extraInfo, roLabel);
- }
- }
- }
-
private void addResolveInfoWithAlternates(ResolvedComponentInfo rci,
CharSequence extraInfo, CharSequence roLabel) {
final int count = rci.getCount();
@@ -1979,31 +1938,32 @@
com.android.internal.R.layout.resolve_list_item, parent, false);
}
- public boolean showsExtendedInfo(TargetInfo info) {
- return !TextUtils.isEmpty(info.getExtendedInfo());
- }
-
public final void bindView(int position, View view) {
onBindView(view, getItem(position));
}
- private void onBindView(View view, TargetInfo info) {
+ protected void onBindView(View view, TargetInfo info) {
final ViewHolder holder = (ViewHolder) view.getTag();
if (info == null) {
holder.icon.setImageDrawable(
getDrawable(R.drawable.resolver_icon_placeholder));
return;
}
+
final CharSequence label = info.getDisplayLabel();
if (!TextUtils.equals(holder.text.getText(), label)) {
holder.text.setText(info.getDisplayLabel());
}
- if (showsExtendedInfo(info)) {
- holder.text2.setVisibility(View.VISIBLE);
- holder.text2.setText(info.getExtendedInfo());
- } else {
- holder.text2.setVisibility(View.GONE);
+
+ // Always show a subLabel for visual consistency across list items. Show an empty
+ // subLabel if the subLabel is the same as the label
+ CharSequence subLabel = info.getExtendedInfo();
+ if (TextUtils.equals(label, subLabel)) subLabel = null;
+
+ if (!TextUtils.equals(holder.text2.getText(), subLabel)) {
+ holder.text2.setText(subLabel);
}
+
if (info instanceof DisplayResolveInfo
&& !((DisplayResolveInfo) info).hasDisplayIcon()) {
new LoadAdapterIconTask((DisplayResolveInfo) info).execute();
diff --git a/core/java/com/android/internal/infra/GlobalWhitelistState.java b/core/java/com/android/internal/infra/GlobalWhitelistState.java
new file mode 100644
index 0000000..dfa59b7
--- /dev/null
+++ b/core/java/com/android/internal/infra/GlobalWhitelistState.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.infra;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Helper class used to manage a {@link WhitelistHelper} per user instance when the main service
+ * cannot hold a lock when external entities (typically {@code ActivityManagerService}) needs to
+ * get whitelist info.
+ *
+ * <p>This class is thread safe.
+ */
+public class GlobalWhitelistState {
+
+ // Uses full-name to avoid collision with service-provided mLock
+ protected final Object mGlobalWhitelistStateLock = new Object();
+
+ @Nullable
+ @GuardedBy("mGlobalWhitelistStateLock")
+ protected SparseArray<WhitelistHelper> mWhitelisterHelpers;
+
+ /**
+ * Sets the whitelist for the given user.
+ */
+ public void setWhitelist(@UserIdInt int userId, @Nullable List<String> packageNames,
+ @Nullable List<ComponentName> components) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (mWhitelisterHelpers == null) {
+ mWhitelisterHelpers = new SparseArray<>(1);
+ }
+ WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+ if (helper == null) {
+ helper = new WhitelistHelper();
+ mWhitelisterHelpers.put(userId, helper);
+ }
+ helper.setWhitelist(packageNames, components);
+ }
+ }
+
+ /**
+ * Checks if the given package is whitelisted for the given user.
+ */
+ public boolean isWhitelisted(@UserIdInt int userId, @NonNull String packageName) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (mWhitelisterHelpers == null) return false;
+ final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+ return helper == null ? false : helper.isWhitelisted(packageName);
+ }
+ }
+
+ /**
+ * Checks if the given component is whitelisted for the given user.
+ */
+ public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (mWhitelisterHelpers == null) return false;
+ final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+ return helper == null ? false : helper.isWhitelisted(componentName);
+ }
+ }
+
+ /**
+ * Gets the whitelisted components for the given package and user.
+ */
+ public ArraySet<ComponentName> getWhitelistedComponents(@UserIdInt int userId,
+ @NonNull String packageName) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (mWhitelisterHelpers == null) return null;
+ final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+ return helper == null ? null : helper.getWhitelistedComponents(packageName);
+ }
+ }
+
+ /**
+ * Resets the whitelist for the given user.
+ */
+ public void resetWhitelist(@NonNull int userId) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (mWhitelisterHelpers == null) return;
+ mWhitelisterHelpers.remove(userId);
+ if (mWhitelisterHelpers.size() == 0) {
+ mWhitelisterHelpers = null;
+ }
+ }
+ }
+
+ /**
+ * Dumps it!
+ */
+ public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ pw.print(prefix); pw.print("State: ");
+ synchronized (mGlobalWhitelistStateLock) {
+ if (mWhitelisterHelpers == null) {
+ pw.println("empty");
+ return;
+ }
+ pw.print(mWhitelisterHelpers.size()); pw.println(" services");
+ final String prefix2 = prefix + " ";
+ for (int i = 0; i < mWhitelisterHelpers.size(); i++) {
+ final int userId = mWhitelisterHelpers.keyAt(i);
+ final WhitelistHelper helper = mWhitelisterHelpers.valueAt(i);
+ helper.dump(prefix2, "Whitelist for userId " + userId, pw);
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/infra/WhitelistHelper.java b/core/java/com/android/internal/infra/WhitelistHelper.java
index 183b465..d7753db 100644
--- a/core/java/com/android/internal/infra/WhitelistHelper.java
+++ b/core/java/com/android/internal/infra/WhitelistHelper.java
@@ -31,6 +31,7 @@
/**
* Helper class for keeping track of whitelisted packages/activities.
*
+ * <p><b>NOTE: </b>this class is not thread safe.
* @hide
*/
public final class WhitelistHelper {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 3303374..e8691fa 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -527,6 +527,13 @@
return (array != null) ? array.clone() : null;
}
+ /**
+ * Clones an array or returns null if the array is null.
+ */
+ public static @Nullable <T> T[] cloneOrNull(@Nullable T[] array) {
+ return (array != null) ? array.clone() : null;
+ }
+
public static @Nullable <T> ArraySet<T> cloneOrNull(@Nullable ArraySet<T> array) {
return (array != null) ? new ArraySet<T>(array) : null;
}
diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java
index 60af511..00e9101 100644
--- a/core/java/com/android/internal/util/SyncResultReceiver.java
+++ b/core/java/com/android/internal/util/SyncResultReceiver.java
@@ -19,10 +19,10 @@
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Parcelable;
-import android.os.RemoteException;
import com.android.internal.os.IResultReceiver;
+import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -97,6 +97,15 @@
}
/**
+ * Gets the result from an operation that returns a {@code Parcelable} list.
+ */
+ @Nullable
+ public <P extends Parcelable> ArrayList<P> getParcelableListResult() throws TimeoutException {
+ waitResult();
+ return mBundle == null ? null : mBundle.getParcelableArrayList(EXTRA);
+ }
+
+ /**
* Gets the optional result from an operation that returns an extra {@code int} (besides the
* result code).
*
@@ -150,6 +159,17 @@
}
/**
+ * Creates a bundle for a {@code Parcelable} list so it can be retrieved by
+ * {@link #getParcelableResult()}.
+ */
+ @NonNull
+ public static Bundle bundleFor(@Nullable ArrayList<? extends Parcelable> value) {
+ final Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(EXTRA, value);
+ return bundle;
+ }
+
+ /**
* Creates a bundle for an {@code int} value so it can be retrieved by
* {@link #getParcelableResult()} - typically used to return an extra {@code int} (as the 1st
* is returned as the result code).
@@ -162,7 +182,7 @@
}
/** @hide */
- public static final class TimeoutException extends RemoteException {
+ public static final class TimeoutException extends RuntimeException {
private TimeoutException(String msg) {
super(msg);
}
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index f40b461..bd4862d 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -106,8 +106,7 @@
static jboolean NativeIsUpToDate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
- (void)apk_assets;
- return JNI_TRUE;
+ return apk_assets->IsUpToDate() ? JNI_TRUE : JNI_FALSE;
}
static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) {
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 88713d1..a296d64 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2229,6 +2229,11 @@
return AudioSystem::isHapticPlaybackSupported();
}
+static jint
+android_media_AudioSystem_setAllowedCapturePolicy(JNIEnv *env, jobject thiz, jint uid, jint flags) {
+ return AudioSystem::setAllowedCapturePolicy(uid, flags);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
@@ -2304,6 +2309,7 @@
{"isHapticPlaybackSupported", "()Z", (void *)android_media_AudioSystem_isHapticPlaybackSupported},
{"getHwOffloadEncodingFormatsSupportedForA2DP", "(Ljava/util/ArrayList;)I",
(void*)android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP},
+ {"setAllowedCapturePolicy", "(II)I", (void *)android_media_AudioSystem_setAllowedCapturePolicy},
};
static const JNINativeMethod gEventHandlerMethods[] = {
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index d7a981e..82acf6f 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -470,6 +470,7 @@
std::vector<uint8_t> buf(MAXPACKETSIZE, 0);
int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE);
+ jniSetFileDescriptorOfFD(env, javaFd, -1);
if (res < 0) {
throwErrnoException(env, "resNetworkResult", -res);
return nullptr;
@@ -490,6 +491,7 @@
static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
int fd = jniGetFDFromFileDescriptor(env, javaFd);
resNetworkCancel(fd);
+ jniSetFileDescriptorOfFD(env, javaFd, -1);
}
static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index bf33ac6..d029527 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2328,4 +2328,7 @@
// OPEN: Settings > System > Aware > Info dialog
DIALOG_AWARE_STATUS = 1701;
+
+ // Open: Settings > app > bubble settings > confirmation dialog
+ DIALOG_APP_BUBBLE_SETTINGS = 1702;
}
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane.xml b/core/res/res/drawable/ic_qs_airplane.xml
similarity index 75%
rename from packages/SystemUI/res/drawable/ic_signal_airplane.xml
rename to core/res/res/drawable/ic_qs_airplane.xml
index f708ed9..166d415 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane.xml
+++ b/core/res/res/drawable/ic_qs_airplane.xml
@@ -15,12 +15,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="18dp"
+ android:height="18dp"
android:viewportWidth="24"
android:viewportHeight="24">
-
-<path
- android:fillColor="#FFFFFF"
- android:pathData="M21,16v-2l-8-5V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-8,5v2l8-2.5V19l-2,1.5V22l3.5-1l3.5,1v-1.5L13,19v-5.5L21,16z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M21,16v-2l-8-5V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-8,5v2l8-2.5V19l-2,1.5V22l3.5-1l3.5,1v-1.5L13,19v-5.5L21,16z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml b/core/res/res/drawable/ic_qs_auto_rotate.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
rename to core/res/res/drawable/ic_qs_auto_rotate.xml
diff --git a/core/res/res/drawable/ic_qs_bluetooth.xml b/core/res/res/drawable/ic_qs_bluetooth.xml
new file mode 100644
index 0000000..91fcff0
--- /dev/null
+++ b/core/res/res/drawable/ic_qs_bluetooth.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane.xml b/core/res/res/drawable/ic_qs_dnd.xml
similarity index 60%
copy from packages/SystemUI/res/drawable/ic_signal_airplane.xml
copy to core/res/res/drawable/ic_qs_dnd.xml
index f708ed9..b361169 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane.xml
+++ b/core/res/res/drawable/ic_qs_dnd.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2019 The Android Open Source Project
+ 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.
@@ -15,12 +14,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
+ android:height="17dp"
+ android:width="17dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0" >
-<path
- android:fillColor="#FFFFFF"
- android:pathData="M21,16v-2l-8-5V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-8,5v2l8-2.5V19l-2,1.5V22l3.5-1l3.5,1v-1.5L13,19v-5.5L21,16z" />
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM7,11h10v2L7,13z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_flashlight.xml b/core/res/res/drawable/ic_qs_flashlight.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_signal_flashlight.xml
rename to core/res/res/drawable/ic_qs_flashlight.xml
diff --git a/core/res/res/drawable/ic_settings_bluetooth.xml b/core/res/res/drawable/ic_settings_bluetooth.xml
index 6e32e1a..91fcff0 100644
--- a/core/res/res/drawable/ic_settings_bluetooth.xml
+++ b/core/res/res/drawable/ic_settings_bluetooth.xml
@@ -14,12 +14,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M13.5,12l3.8,-3.7c0.4,-0.4 0.4,-1.1 0,-1.5l-4.5,-4.5c-0.4,-0.4 -1.1,-0.4 -1.5,0.1C11.1,2.5 11,2.8 11,3v6.4L6.9,5.4C6.5,5 5.9,5 5.5,5.4s-0.4,1.1 0,1.5l5.1,5.1l-5.1,5.1c-0.4,0.4 -0.4,1.1 0,1.5s1.1,0.4 1.5,0l4.1,-4V21c0,0.6 0.5,1 1,1c0.3,0 0.5,-0.1 0.7,-0.3l0.1,0l4.5,-4.5c0.4,-0.4 0.4,-1.1 0,-1.5L13.5,12zM13,9.7V5.4l2.1,2.2L13,9.7zM13,18.6v-4.3l2.1,2.2L13,18.6z"/>
-</vector>
+ android:fillColor="@android:color/white"
+ android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml
index 4a3dfba..7065149 100644
--- a/core/res/res/layout/resolve_grid_item.xml
+++ b/core/res/res/layout/resolve_grid_item.xml
@@ -22,46 +22,43 @@
android:layout_height="wrap_content"
android:minHeight="100dp"
android:gravity="center"
- android:paddingTop="8dp"
+ android:paddingTop="24dp"
android:paddingBottom="8dp"
+ android:paddingLeft="2dp"
+ android:paddingRight="2dp"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless">
<ImageView android:id="@+id/icon"
android:layout_width="@dimen/resolver_icon_size"
android:layout_height="@dimen/resolver_icon_size"
- android:layout_marginLeft="3dp"
- android:layout_marginRight="3dp"
- android:layout_marginBottom="3dp"
android:scaleType="fitCenter" />
- <!-- Activity name -->
+ <!-- Size manually tuned to match specs -->
+ <Space android:layout_width="1dp"
+ android:layout_height="7dp"/>
+
+ <!-- App name or Direct Share target name, DS set to 2 lines -->
<TextView android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
android:textAppearance="?attr/textAppearanceSmall"
android:textColor="?attr/textColorPrimary"
- android:textSize="12sp"
+ android:textSize="14sp"
android:fontFamily="sans-serif-condensed"
android:gravity="top|center_horizontal"
- android:minLines="2"
- android:maxLines="2"
- android:ellipsize="marquee" />
- <!-- Extended activity info to distinguish between duplicate activity names -->
+ android:lines="1"
+ android:ellipsize="end" />
+
+ <!-- Activity name if set, gone for Direct Share targets -->
<TextView android:id="@android:id/text2"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="12sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
- android:minLines="2"
- android:maxLines="2"
+ android:lines="1"
android:gravity="top|center_horizontal"
- android:ellipsize="marquee"
- android:visibility="gone" />
+ android:ellipsize="end"/>
+
</LinearLayout>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 362d01c..8f3f25a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1687,6 +1687,17 @@
- {@code false} for apps with targetSdkVersion < 29.
-->
<attr name="allowAudioPlaybackCapture" format="boolean" />
+ <!-- If {@code true} this app allows shared/external storage media to be
+ a sandboxed view that only contains files owned by the app.
+ <p>
+ Sandboxed apps can continue to discover and read media belonging to other
+ apps via {@code MediaStore}.
+ <p>
+ The default value is:
+ - {@code true} for apps with targetSdkVersion >= 29 (Q).
+ - {@code false} for apps with targetSdkVersion < 29.
+ -->
+ <attr name="allowExternalStorageSandbox" format="boolean" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 41d9dbc..2139453 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3983,6 +3983,9 @@
<!-- Whether or not to enable automatic heap dumps for the system server on debuggable builds. -->
<bool name="config_debugEnableAutomaticSystemServerHeapDumps">false</bool>
+ <!-- Trigger a heap dump if the system server pss usage exceeds this threshold. 400 MB -->
+ <integer name="config_debugSystemServerPssThresholdBytes">419430400</integer>
+
<!-- See DropBoxManagerService.
The minimum period in milliseconds between broadcasts for entries with low priority
dropbox tags. -->
@@ -3993,8 +3996,14 @@
rated limited to a period defined by config_dropboxLowPriorityBroadcastRateLimitPeriod
(high frequency broadcasts for the tag will be dropped) -->
<string-array name="config_dropboxLowPriorityTags" translatable="false">
+ <item>data_app_strictmode</item>
+ <item>data_app_wtf</item>
<item>keymaster</item>
+ <item>netstats</item>
+ <item>system_app_strictmode</item>
+ <item>system_app_wtf</item>
<item>system_server_strictmode</item>
+ <item>system_server_wtf</item>
</string-array>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3505994..3bbc03f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2942,6 +2942,7 @@
<public name="allowClearUserDataOnFailedRestore"/>
<public name="allowAudioPlaybackCapture"/>
<public name="secureElementName" />
+ <public name="allowExternalStorageSandbox"/>
</public-group>
<public-group type="drawable" first-id="0x010800b4">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 45494a0..03259ed 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1582,25 +1582,25 @@
</string-array>
<!-- Error message shown when the face hardware can't be accessed. [CHAR LIMIT=50] -->
- <string name="face_error_hw_not_available">Face hardware not available.</string>
+ <string name="face_error_hw_not_available">Can\u2019t verify face. Hardware not available.</string>
<!-- Error message shown when the face hardware timer has expired and the user needs to restart the operation. [CHAR LIMIT=50] -->
<string name="face_error_timeout">Face timeout reached. Try again.</string>
- <!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=50] -->
- <string name="face_error_no_space">Face can\u2019t be stored.</string>
+ <!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=60] -->
+ <string name="face_error_no_space">Can\u2019t store new face data. Delete an old one first.</string>
<!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
- <string name="face_error_canceled">Face operation canceled.</string>
+ <string name="face_error_canceled">Face operation canceled</string>
<!-- Generic error message shown when the face authentication operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=50] -->
- <string name="face_error_user_canceled">Face authentication canceled by user.</string>
+ <string name="face_error_user_canceled">Face authentication canceled by user</string>
<!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
<string name="face_error_lockout">Too many attempts. Try again later.</string>
- <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=50] -->
- <string name="face_error_lockout_permanent">Too many attempts. Facial authentication disabled.</string>
+ <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=60] -->
+ <string name="face_error_lockout_permanent">Too many attempts. Face authentication disabled.</string>
<!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
<string name="face_error_unable_to_process">Can\u2019t verify face. Try again.</string>
<!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=50] -->
- <string name="face_error_not_enrolled">You haven\u2019t set up face authentication.</string>
+ <string name="face_error_not_enrolled">You haven\u2019t set up face authentication</string>
<!-- Generic error message shown when the app requests face authentication on a device without a sensor. [CHAR LIMIT=60] -->
- <string name="face_error_hw_not_present">Face authentication is not supported on this device.</string>
+ <string name="face_error_hw_not_present">Face authentication is not supported on this device</string>
<!-- Template to be used to name enrolled faces by default. [CHAR LIMIT=10] -->
<string name="face_name_template">Face <xliff:g id="faceId" example="1">%d</xliff:g></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7a473d2..4188bd4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1443,6 +1443,11 @@
<java-symbol type="drawable" name="ic_instant_icon_badge_bolt" />
<java-symbol type="drawable" name="emulator_circular_window_overlay" />
<java-symbol type="drawable" name="ic_qs_battery_saver" />
+ <java-symbol type="drawable" name="ic_qs_bluetooth" />
+ <java-symbol type="drawable" name="ic_qs_airplane" />
+ <java-symbol type="drawable" name="ic_qs_flashlight" />
+ <java-symbol type="drawable" name="ic_qs_auto_rotate" />
+ <java-symbol type="drawable" name="ic_qs_dnd" />
<java-symbol type="drawable" name="sim_light_blue" />
<java-symbol type="drawable" name="sim_light_green" />
@@ -3225,6 +3230,7 @@
<java-symbol type="bool" name="config_batterymeterDualTone" />
<java-symbol type="bool" name="config_debugEnableAutomaticSystemServerHeapDumps" />
+ <java-symbol type="integer" name="config_debugSystemServerPssThresholdBytes" />
<!-- Accessibility Shortcut -->
<java-symbol type="string" name="accessibility_shortcut_warning_dialog_title" />
diff --git a/core/tests/coretests/src/android/view/ViewGroupTest.java b/core/tests/coretests/src/android/view/ViewGroupTest.java
new file mode 100644
index 0000000..979a839
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewGroupTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.graphics.Region;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+
+/**
+ * Test basic functions of ViewGroup.
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:ViewGroupTest
+ */
+@Presubmit
+@SmallTest
+public class ViewGroupTest {
+
+ /**
+ * Test if {@link ViewGroup#subtractObscuredTouchableRegion} works as expected.
+ *
+ * The view hierarchy:
+ * A---B---C
+ * \ \
+ * \ --D
+ * \
+ * E---F
+ *
+ * The layer and bounds of each view:
+ * F -- (invisible)
+ * E --
+ * D ----
+ * C ----------
+ * B ------
+ * A --------
+ */
+ @Test
+ public void testSubtractObscuredTouchableRegion() {
+ final Context context = getContext();
+ final TestView viewA = new TestView(context, 8 /* right */);
+ final TestView viewB = new TestView(context, 6 /* right */);
+ final TestView viewC = new TestView(context, 10 /* right */);
+ final TestView viewD = new TestView(context, 4 /* right */);
+ final TestView viewE = new TestView(context, 2 /* right */);
+ final TestView viewF = new TestView(context, 2 /* right */);
+
+ viewA.addView(viewB);
+ viewA.addView(viewE);
+ viewB.addView(viewC);
+ viewB.addView(viewD);
+ viewE.addView(viewF);
+
+ viewF.setVisibility(View.INVISIBLE);
+
+ final Region r = new Region();
+
+ getUnobscuredTouchableRegion(r, viewA);
+ assertRegionContainPoint(1 /* x */, r, true /* contain */);
+ assertRegionContainPoint(3 /* x */, r, true /* contain */);
+ assertRegionContainPoint(5 /* x */, r, true /* contain */);
+ assertRegionContainPoint(7 /* x */, r, true /* contain */);
+ assertRegionContainPoint(9 /* x */, r, false /* contain */); // Outside of bounds
+
+ getUnobscuredTouchableRegion(r, viewB);
+ assertRegionContainPoint(1 /* x */, r, false /* contain */); // Obscured by E
+ assertRegionContainPoint(3 /* x */, r, true /* contain */);
+ assertRegionContainPoint(5 /* x */, r, true /* contain */);
+ assertRegionContainPoint(7 /* x */, r, false /* contain */); // Outside of bounds
+
+ getUnobscuredTouchableRegion(r, viewC);
+ assertRegionContainPoint(1 /* x */, r, false /* contain */); // Obscured by D and E
+ assertRegionContainPoint(3 /* x */, r, false /* contain */); // Obscured by D
+ assertRegionContainPoint(5 /* x */, r, true /* contain */);
+ assertRegionContainPoint(7 /* x */, r, false /* contain */); // Outside of parent bounds
+
+ getUnobscuredTouchableRegion(r, viewD);
+ assertRegionContainPoint(1 /* x */, r, false /* contain */); // Obscured by E
+ assertRegionContainPoint(3 /* x */, r, true /* contain */);
+ assertRegionContainPoint(5 /* x */, r, false /* contain */); // Outside of bounds
+
+ getUnobscuredTouchableRegion(r, viewE);
+ assertRegionContainPoint(1 /* x */, r, true /* contain */);
+ assertRegionContainPoint(3 /* x */, r, false /* contain */); // Outside of bounds
+ }
+
+ private static void getUnobscuredTouchableRegion(Region outRegion, View view) {
+ outRegion.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+ final ViewParent parent = view.getParent();
+ if (parent != null) {
+ parent.subtractObscuredTouchableRegion(outRegion, view);
+ }
+ }
+
+ private static void assertRegionContainPoint(int x, Region region, boolean contain) {
+ assertEquals(String.format("Touchable region must%s contain (%s, 0).",
+ (contain ? "" : " not"), x), contain, region.contains(x, 0 /* y */));
+ }
+
+ private static class TestView extends ViewGroup {
+ TestView(Context context, int right) {
+ super(context);
+ setFrame(0 /* left */, 0 /* top */, right, 1 /* bottom */);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ // We don't layout this view.
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
index 2416de1..2008537 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
@@ -49,13 +49,15 @@
private static final LocusId ID = new LocusId("WHATEVER");
+ private static final int NO_SESSION_ID = 0;
+
// Not using @Mock because it's final - no need to be fancy here....
private final ContentCaptureContext mClientContext =
new ContentCaptureContext.Builder(ID).build();
@Test
public void testSetAutofillId_null() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
assertThrows(NullPointerException.class, () -> event.setAutofillId(null));
assertThat(event.getId()).isNull();
@@ -64,7 +66,7 @@
@Test
public void testSetAutofillIds_null() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
assertThrows(NullPointerException.class, () -> event.setAutofillIds(null));
assertThat(event.getId()).isNull();
@@ -73,7 +75,7 @@
@Test
public void testAddAutofillId_null() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
assertThrows(NullPointerException.class, () -> event.addAutofillId(null));
assertThat(event.getId()).isNull();
@@ -82,7 +84,7 @@
@Test
public void testSetAutofillId() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
final AutofillId id = new AutofillId(108);
event.setAutofillId(id);
@@ -92,7 +94,7 @@
@Test
public void testSetAutofillIds() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
final AutofillId id = new AutofillId(108);
final ArrayList<AutofillId> ids = new ArrayList<>(1);
@@ -104,7 +106,7 @@
@Test
public void testAddAutofillId() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
final AutofillId id1 = new AutofillId(108);
event.addAutofillId(id1);
@@ -119,7 +121,7 @@
@Test
public void testAddAutofillId_afterSetId() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
final AutofillId id1 = new AutofillId(108);
event.setAutofillId(id1);
@@ -134,7 +136,7 @@
@Test
public void testAddAutofillId_afterSetIds() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
final AutofillId id1 = new AutofillId(108);
final ArrayList<AutofillId> ids = new ArrayList<>(1);
@@ -163,9 +165,9 @@
}
private ContentCaptureEvent newEventForSessionStarted() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_STARTED)
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_SESSION_STARTED)
.setClientContext(mClientContext)
- .setParentSessionId("108");
+ .setParentSessionId(108);
assertThat(event).isNotNull();
return event;
}
@@ -173,8 +175,8 @@
private void assertSessionStartedEvent(ContentCaptureEvent event) {
assertThat(event.getType()).isEqualTo(TYPE_SESSION_STARTED);
assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
- assertThat(event.getSessionId()).isEqualTo("42");
- assertThat(event.getParentSessionId()).isEqualTo("108");
+ assertThat(event.getSessionId()).isEqualTo(42);
+ assertThat(event.getParentSessionId()).isEqualTo(108);
assertThat(event.getId()).isNull();
assertThat(event.getIds()).isNull();
assertThat(event.getText()).isNull();
@@ -186,17 +188,17 @@
@Test
public void testSessionFinished_directly() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_FINISHED)
- .setParentSessionId("108");
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_SESSION_FINISHED)
+ .setParentSessionId(108);
assertThat(event).isNotNull();
assertSessionFinishedEvent(event);
}
@Test
public void testSessionFinished_throughParcel() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_FINISHED)
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_SESSION_FINISHED)
.setClientContext(mClientContext) // should not be writting to parcel
- .setParentSessionId("108");
+ .setParentSessionId(108);
assertThat(event).isNotNull();
final ContentCaptureEvent clone = cloneThroughParcel(event);
assertSessionFinishedEvent(clone);
@@ -205,8 +207,8 @@
private void assertSessionFinishedEvent(ContentCaptureEvent event) {
assertThat(event.getType()).isEqualTo(TYPE_SESSION_FINISHED);
assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
- assertThat(event.getSessionId()).isEqualTo("42");
- assertThat(event.getParentSessionId()).isEqualTo("108");
+ assertThat(event.getSessionId()).isEqualTo(42);
+ assertThat(event.getParentSessionId()).isEqualTo(108);
assertThat(event.getId()).isNull();
assertThat(event.getIds()).isNull();
assertThat(event.getText()).isNull();
@@ -216,7 +218,7 @@
@Test
public void testContextUpdated_directly() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_CONTEXT_UPDATED)
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_CONTEXT_UPDATED)
.setClientContext(mClientContext);
assertThat(event).isNotNull();
assertContextUpdatedEvent(event);
@@ -224,7 +226,7 @@
@Test
public void testContextUpdated_throughParcel() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_CONTEXT_UPDATED)
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_CONTEXT_UPDATED)
.setClientContext(mClientContext);
assertThat(event).isNotNull();
final ContentCaptureEvent clone = cloneThroughParcel(event);
@@ -233,9 +235,9 @@
@Test
public void testMergeEvent_typeViewTextChanged() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_TEXT_CHANGED)
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_TEXT_CHANGED)
.setText("test");
- final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_TEXT_CHANGED)
+ final ContentCaptureEvent event2 = new ContentCaptureEvent(43, TYPE_VIEW_TEXT_CHANGED)
.setText("empty");
event.mergeEvent(event2);
@@ -244,14 +246,14 @@
@Test
public void testMergeEvent_typeViewDisappeared() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED)
.setAutofillId(new AutofillId(1));
- final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_DISAPPEARED)
+ final ContentCaptureEvent event2 = new ContentCaptureEvent(43, TYPE_VIEW_DISAPPEARED)
.setAutofillId(new AutofillId(2));
final ArrayList<AutofillId> autofillIds = new ArrayList<>();
autofillIds.add(new AutofillId(3));
autofillIds.add(new AutofillId(4));
- final ContentCaptureEvent event3 = new ContentCaptureEvent("17", TYPE_VIEW_DISAPPEARED)
+ final ContentCaptureEvent event3 = new ContentCaptureEvent(17, TYPE_VIEW_DISAPPEARED)
.setAutofillIds(autofillIds);
event.mergeEvent(event2);
@@ -264,24 +266,24 @@
@Test
public void testMergeEvent_typeViewDisappeared_noIds() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED)
.setAutofillId(new AutofillId(1));
- final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_DISAPPEARED);
+ final ContentCaptureEvent event2 = new ContentCaptureEvent(43, TYPE_VIEW_DISAPPEARED);
assertThrows(IllegalArgumentException.class, () -> event.mergeEvent(event2));
}
@Test
public void testMergeEvent_nullArgument() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
assertThrows(NullPointerException.class, () -> event.mergeEvent(null));
}
@Test
public void testMergeEvent_differentEventTypes() {
- final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+ final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED)
.setText("test").setAutofillId(new AutofillId(1));
- final ContentCaptureEvent event2 = new ContentCaptureEvent("17", TYPE_VIEW_TEXT_CHANGED)
+ final ContentCaptureEvent event2 = new ContentCaptureEvent(17, TYPE_VIEW_TEXT_CHANGED)
.setText("empty").setAutofillId(new AutofillId(2));
event.mergeEvent(event2);
@@ -296,8 +298,8 @@
private void assertContextUpdatedEvent(ContentCaptureEvent event) {
assertThat(event.getType()).isEqualTo(TYPE_CONTEXT_UPDATED);
assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
- assertThat(event.getSessionId()).isEqualTo("42");
- assertThat(event.getParentSessionId()).isNull();
+ assertThat(event.getSessionId()).isEqualTo(42);
+ assertThat(event.getParentSessionId()).isEqualTo(NO_SESSION_ID);
assertThat(event.getId()).isNull();
assertThat(event.getIds()).isNull();
assertThat(event.getText()).isNull();
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 013408e..81ce15a 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -39,9 +39,9 @@
@RunWith(MockitoJUnitRunner.class)
public class ContentCaptureSessionTest {
- private ContentCaptureSession mSession1 = new MyContentCaptureSession("111");
+ private ContentCaptureSession mSession1 = new MyContentCaptureSession(111);
- private ContentCaptureSession mSession2 = new MyContentCaptureSession("2222");
+ private ContentCaptureSession mSession2 = new MyContentCaptureSession(2222);
@Mock
private View mMockView;
@@ -60,12 +60,12 @@
assertThat(childId.getViewId()).isEqualTo(42);
assertThat(childId.getVirtualChildLongId()).isEqualTo(108L);
assertThat(childId.getVirtualChildIntId()).isEqualTo(View.NO_ID);
- assertThat(childId.getSessionId()).isEqualTo(mSession1.getIdAsInt());
+ assertThat(childId.getSessionId()).isEqualTo(mSession1.getId());
}
@Test
public void testNewAutofillId_differentSessions() {
- assertThat(mSession1.getIdAsInt()).isNotSameAs(mSession2.getIdAsInt()); //sanity check
+ assertThat(mSession1.getId()).isNotEqualTo(mSession2.getId()); //sanity check
final AutofillId parentId = new AutofillId(42);
final AutofillId childId1 = mSession1.newAutofillId(parentId, 108L);
final AutofillId childId2 = mSession2.newAutofillId(parentId, 108L);
@@ -117,7 +117,7 @@
// Cannot use @Spy because we need to pass the session id on constructor
private class MyContentCaptureSession extends ContentCaptureSession {
- private MyContentCaptureSession(String id) {
+ private MyContentCaptureSession(int id) {
super(id);
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 7430c7a..453bddd 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -23,6 +23,7 @@
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static com.android.internal.app.ResolverDataProvider.createPackageManagerMockedInfo;
import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
import static org.hamcrest.CoreMatchers.is;
@@ -32,6 +33,7 @@
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import android.text.TextUtils;
import android.view.View;
import android.widget.RelativeLayout;
@@ -40,7 +42,10 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import com.android.internal.app.ResolverActivity.ActivityInfoPresentationGetter;
+import com.android.internal.app.ResolverActivity.ResolveInfoPresentationGetter;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import com.android.internal.app.ResolverDataProvider.PackageManagerMockedInfo;
import com.android.internal.widget.ResolverDrawerLayout;
import org.junit.Before;
@@ -319,6 +324,50 @@
assertThat(chosen[0], is(toChoose));
}
+ @Test
+ public void getActivityLabelAndSubLabel() throws Exception {
+ ActivityInfoPresentationGetter pg;
+ PackageManagerMockedInfo info;
+
+ info = createPackageManagerMockedInfo(false);
+ pg = new ActivityInfoPresentationGetter(
+ info.ctx, 0, info.activityInfo);
+ assertThat("Label should match app label", pg.getLabel().equals(
+ info.setAppLabel));
+ assertThat("Sublabel should match activity label if set",
+ pg.getSubLabel().equals(info.setActivityLabel));
+
+ info = createPackageManagerMockedInfo(true);
+ pg = new ActivityInfoPresentationGetter(
+ info.ctx, 0, info.activityInfo);
+ assertThat("With override permission label should match activity label if set",
+ pg.getLabel().equals(info.setActivityLabel));
+ assertThat("With override permission sublabel should be empty",
+ TextUtils.isEmpty(pg.getSubLabel()));
+ }
+
+ @Test
+ public void getResolveInfoLabelAndSubLabel() throws Exception {
+ ResolveInfoPresentationGetter pg;
+ PackageManagerMockedInfo info;
+
+ info = createPackageManagerMockedInfo(false);
+ pg = new ResolveInfoPresentationGetter(
+ info.ctx, 0, info.resolveInfo);
+ assertThat("Label should match app label", pg.getLabel().equals(
+ info.setAppLabel));
+ assertThat("Sublabel should match resolve info label if set",
+ pg.getSubLabel().equals(info.setResolveInfoLabel));
+
+ info = createPackageManagerMockedInfo(true);
+ pg = new ResolveInfoPresentationGetter(
+ info.ctx, 0, info.resolveInfo);
+ assertThat("With override permission label should match resolve info label if set",
+ pg.getLabel().equals(info.setResolveInfoLabel));
+ assertThat("With override permission sublabel should be empty",
+ TextUtils.isEmpty(pg.getSubLabel()));
+ }
+
private Intent createSendImageIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
index 850b466..59634f6 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
@@ -17,11 +17,17 @@
package com.android.internal.app;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.os.UserHandle;
+import android.test.mock.MockContext;
+import android.test.mock.MockPackageManager;
+import android.test.mock.MockResources;
/**
* Utility class used by resolver tests to create mock data
@@ -71,6 +77,86 @@
return ai;
}
+ static class PackageManagerMockedInfo {
+ public Context ctx;
+ public ApplicationInfo appInfo;
+ public ActivityInfo activityInfo;
+ public ResolveInfo resolveInfo;
+ public String setAppLabel;
+ public String setActivityLabel;
+ public String setResolveInfoLabel;
+ }
+
+ static PackageManagerMockedInfo createPackageManagerMockedInfo(boolean hasOverridePermission) {
+ final String appLabel = "app_label";
+ final String activityLabel = "activity_label";
+ final String resolveInfoLabel = "resolve_info_label";
+
+ MockContext ctx = new MockContext() {
+ @Override
+ public PackageManager getPackageManager() {
+ return new MockPackageManager() {
+ @Override
+ public int checkPermission(String permName, String pkgName) {
+ if (hasOverridePermission) return PERMISSION_GRANTED;
+ return PERMISSION_DENIED;
+ }
+ };
+ }
+
+ @Override
+ public Resources getResources() {
+ return new MockResources() {
+ @Override
+ public String getString(int id) throws NotFoundException {
+ if (id == 1) return appLabel;
+ if (id == 2) return activityLabel;
+ if (id == 3) return resolveInfoLabel;
+ return null;
+ }
+ };
+ }
+ };
+
+ ApplicationInfo appInfo = new ApplicationInfo() {
+ @Override
+ public CharSequence loadLabel(PackageManager pm) {
+ return appLabel;
+ }
+ };
+ appInfo.labelRes = 1;
+
+ ActivityInfo activityInfo = new ActivityInfo() {
+ @Override
+ public CharSequence loadLabel(PackageManager pm) {
+ return activityLabel;
+ }
+ };
+ activityInfo.labelRes = 2;
+ activityInfo.applicationInfo = appInfo;
+
+ ResolveInfo resolveInfo = new ResolveInfo() {
+ @Override
+ public CharSequence loadLabel(PackageManager pm) {
+ return resolveInfoLabel;
+ }
+ };
+ resolveInfo.activityInfo = activityInfo;
+ resolveInfo.resolvePackageName = "super.fake.packagename";
+ resolveInfo.labelRes = 3;
+
+ PackageManagerMockedInfo mockedInfo = new PackageManagerMockedInfo();
+ mockedInfo.activityInfo = activityInfo;
+ mockedInfo.appInfo = appInfo;
+ mockedInfo.ctx = ctx;
+ mockedInfo.resolveInfo = resolveInfo;
+ mockedInfo.setAppLabel = appLabel;
+ mockedInfo.setActivityLabel = activityLabel;
+ mockedInfo.setResolveInfoLabel = resolveInfoLabel;
+
+ return mockedInfo;
+ }
+
static Intent createResolverIntent(int i) {
return new Intent("intentAction" + i);
}
diff --git a/core/xsd/Android.bp b/core/xsd/Android.bp
index 81669eb..738f330 100644
--- a/core/xsd/Android.bp
+++ b/core/xsd/Android.bp
@@ -2,5 +2,5 @@
name: "permission",
srcs: ["permission.xsd"],
api_dir: "schema",
- package_name: "com.android.xml.permission",
+ package_name: "com.android.xml.permission.configfile",
}
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index 1228124..2ef2d04 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -78,6 +78,7 @@
<xs:complexType name="feature">
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="notLowRam" type="xs:string"/>
+ <xs:attribute name="version" type="xs:int"/>
</xs:complexType>
<xs:complexType name="unavailable-feature">
<xs:attribute name="name" type="xs:string"/>
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index 82bb0fea..c25bc14 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -1,5 +1,5 @@
// Signature format: 2.0
-package com.android.xml.permission {
+package com.android.xml.permission.configfile {
public class AllowAssociation {
ctor public AllowAssociation();
@@ -97,8 +97,10 @@
ctor public Feature();
method public String getName();
method public String getNotLowRam();
+ method public int getVersion();
method public void setName(String);
method public void setNotLowRam(String);
+ method public void setVersion(int);
}
public class Group {
@@ -125,8 +127,8 @@
public class OemPermissions {
ctor public OemPermissions();
- method public java.util.List<com.android.xml.permission.OemPermissions.DenyPermission> getDenyPermission();
- method public java.util.List<com.android.xml.permission.OemPermissions.Permission> getPermission();
+ method public java.util.List<com.android.xml.permission.configfile.OemPermissions.DenyPermission> getDenyPermission();
+ method public java.util.List<com.android.xml.permission.configfile.OemPermissions.Permission> getPermission();
method public String get_package();
method public void set_package(String);
}
@@ -151,37 +153,37 @@
public class Permissions {
ctor public Permissions();
- method public java.util.List<com.android.xml.permission.AllowAssociation> getAllowAssociation();
- method public java.util.List<com.android.xml.permission.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings();
- method public java.util.List<com.android.xml.permission.AllowImplicitBroadcast> getAllowImplicitBroadcast();
- method public java.util.List<com.android.xml.permission.AllowInDataUsageSave> getAllowInDataUsageSave();
- method public java.util.List<com.android.xml.permission.AllowInPowerSave> getAllowInPowerSave();
- method public java.util.List<com.android.xml.permission.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle();
- method public java.util.List<com.android.xml.permission.AllowUnthrottledLocation> getAllowUnthrottledLocation();
- method public java.util.List<com.android.xml.permission.AppLink> getAppLink();
- method public java.util.List<com.android.xml.permission.AssignPermission> getAssignPermission();
- method public java.util.List<com.android.xml.permission.BackupTransportWhitelistedService> getBackupTransportWhitelistedService();
- method public java.util.List<com.android.xml.permission.BugreportWhitelisted> getBugreportWhitelisted();
- method public java.util.List<com.android.xml.permission.DefaultEnabledVrApp> getDefaultEnabledVrApp();
- method public java.util.List<com.android.xml.permission.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp();
- method public java.util.List<com.android.xml.permission.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp();
- method public java.util.List<com.android.xml.permission.Feature> getFeature();
- method public java.util.List<com.android.xml.permission.Group> getGroup();
- method public java.util.List<com.android.xml.permission.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp();
- method public java.util.List<com.android.xml.permission.Library> getLibrary();
- method public java.util.List<com.android.xml.permission.OemPermissions> getOemPermissions();
- method public java.util.List<com.android.xml.permission.Permission> getPermission();
- method public java.util.List<com.android.xml.permission.PrivappPermissions> getPrivappPermissions();
- method public java.util.List<com.android.xml.permission.SplitPermission> getSplitPermission();
- method public java.util.List<com.android.xml.permission.SystemUserBlacklistedApp> getSystemUserBlacklistedApp();
- method public java.util.List<com.android.xml.permission.SystemUserWhitelistedApp> getSystemUserWhitelistedApp();
- method public java.util.List<com.android.xml.permission.UnavailableFeature> getUnavailableFeature();
+ method public java.util.List<com.android.xml.permission.configfile.AllowAssociation> getAllowAssociation();
+ method public java.util.List<com.android.xml.permission.configfile.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings();
+ method public java.util.List<com.android.xml.permission.configfile.AllowImplicitBroadcast> getAllowImplicitBroadcast();
+ method public java.util.List<com.android.xml.permission.configfile.AllowInDataUsageSave> getAllowInDataUsageSave();
+ method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave();
+ method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle();
+ method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation();
+ method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink();
+ method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission();
+ method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService();
+ method public java.util.List<com.android.xml.permission.configfile.BugreportWhitelisted> getBugreportWhitelisted();
+ method public java.util.List<com.android.xml.permission.configfile.DefaultEnabledVrApp> getDefaultEnabledVrApp();
+ method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp();
+ method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp();
+ method public java.util.List<com.android.xml.permission.configfile.Feature> getFeature();
+ method public java.util.List<com.android.xml.permission.configfile.Group> getGroup();
+ method public java.util.List<com.android.xml.permission.configfile.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp();
+ method public java.util.List<com.android.xml.permission.configfile.Library> getLibrary();
+ method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions();
+ method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission();
+ method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions();
+ method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission();
+ method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp();
+ method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp();
+ method public java.util.List<com.android.xml.permission.configfile.UnavailableFeature> getUnavailableFeature();
}
public class PrivappPermissions {
ctor public PrivappPermissions();
- method public java.util.List<com.android.xml.permission.PrivappPermissions.DenyPermission> getDenyPermission();
- method public java.util.List<com.android.xml.permission.PrivappPermissions.Permission> getPermission();
+ method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions.DenyPermission> getDenyPermission();
+ method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions.Permission> getPermission();
method public String get_package();
method public void set_package(String);
}
@@ -200,7 +202,7 @@
public class SplitPermission {
ctor public SplitPermission();
- method public java.util.List<com.android.xml.permission.SplitPermission.Library> getLibrary();
+ method public java.util.List<com.android.xml.permission.configfile.SplitPermission.Library> getLibrary();
method public String getName();
method public int getTargetSdk();
method public void setName(String);
@@ -233,7 +235,7 @@
public class XmlParser {
ctor public XmlParser();
- method public static com.android.xml.permission.Permissions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static com.android.xml.permission.configfile.Permissions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 347edc5..3c8794f 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -271,7 +271,10 @@
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.MOVE_PACKAGE"/>
<permission name="android.permission.OBSERVE_APP_USAGE"/>
+ <permission name="android.permission.NETWORK_SCAN"/>
<permission name="android.permission.PACKAGE_USAGE_STATS" />
+ <!-- Needed for test only -->
+ <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
<permission name="android.permission.POWER_SAVER" />
<permission name="android.permission.READ_FRAME_BUFFER"/>
<permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index cdb3441..6948bc4 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -1312,6 +1312,10 @@
y0 = r.top + (r.bottom - r.top) * st.mCenterY;
float radius = st.mGradientRadius;
+ if (Float.compare(radius, 0.0f) == -1 || Float.isNaN(radius)) {
+ throw new IllegalArgumentException("Gradient radius must be a valid "
+ + "number greater than or equal to 0");
+ }
if (st.mGradientRadiusType == RADIUS_TYPE_FRACTION) {
// Fall back to parent width or height if intrinsic
// size is not specified.
@@ -1759,75 +1763,68 @@
st.mGradientColors[1] = endColor;
}
- if (st.mGradient == LINEAR_GRADIENT) {
- int angle = (int) a.getFloat(R.styleable.GradientDrawableGradient_angle, st.mAngle);
- angle %= 360;
+ int angle = (int) a.getFloat(R.styleable.GradientDrawableGradient_angle, st.mAngle);
+ angle %= 360;
- if (angle % 45 != 0) {
- throw new XmlPullParserException(a.getPositionDescription()
- + "<gradient> tag requires 'angle' attribute to "
- + "be a multiple of 45");
- }
+ if (angle % 45 != 0) {
+ throw new XmlPullParserException(a.getPositionDescription()
+ + "<gradient> tag requires 'angle' attribute to "
+ + "be a multiple of 45");
+ }
- st.mAngle = angle;
+ st.mAngle = angle;
- switch (angle) {
- case 0:
- st.mOrientation = Orientation.LEFT_RIGHT;
- break;
- case 45:
- st.mOrientation = Orientation.BL_TR;
- break;
- case 90:
- st.mOrientation = Orientation.BOTTOM_TOP;
- break;
- case 135:
- st.mOrientation = Orientation.BR_TL;
- break;
- case 180:
- st.mOrientation = Orientation.RIGHT_LEFT;
- break;
- case 225:
- st.mOrientation = Orientation.TR_BL;
- break;
- case 270:
- st.mOrientation = Orientation.TOP_BOTTOM;
- break;
- case 315:
- st.mOrientation = Orientation.TL_BR;
- break;
- }
- } else {
- final TypedValue tv = a.peekValue(R.styleable.GradientDrawableGradient_gradientRadius);
- if (tv != null) {
- final float radius;
- final @RadiusType int radiusType;
- if (tv.type == TypedValue.TYPE_FRACTION) {
- radius = tv.getFraction(1.0f, 1.0f);
+ switch (angle) {
+ case 0:
+ st.mOrientation = Orientation.LEFT_RIGHT;
+ break;
+ case 45:
+ st.mOrientation = Orientation.BL_TR;
+ break;
+ case 90:
+ st.mOrientation = Orientation.BOTTOM_TOP;
+ break;
+ case 135:
+ st.mOrientation = Orientation.BR_TL;
+ break;
+ case 180:
+ st.mOrientation = Orientation.RIGHT_LEFT;
+ break;
+ case 225:
+ st.mOrientation = Orientation.TR_BL;
+ break;
+ case 270:
+ st.mOrientation = Orientation.TOP_BOTTOM;
+ break;
+ case 315:
+ st.mOrientation = Orientation.TL_BR;
+ break;
+ }
- final int unit = (tv.data >> TypedValue.COMPLEX_UNIT_SHIFT)
- & TypedValue.COMPLEX_UNIT_MASK;
- if (unit == TypedValue.COMPLEX_UNIT_FRACTION_PARENT) {
- radiusType = RADIUS_TYPE_FRACTION_PARENT;
- } else {
- radiusType = RADIUS_TYPE_FRACTION;
- }
- } else if (tv.type == TypedValue.TYPE_DIMENSION) {
- radius = tv.getDimension(r.getDisplayMetrics());
- radiusType = RADIUS_TYPE_PIXELS;
+ final TypedValue tv = a.peekValue(R.styleable.GradientDrawableGradient_gradientRadius);
+ if (tv != null) {
+ final float radius;
+ final @RadiusType int radiusType;
+ if (tv.type == TypedValue.TYPE_FRACTION) {
+ radius = tv.getFraction(1.0f, 1.0f);
+
+ final int unit = (tv.data >> TypedValue.COMPLEX_UNIT_SHIFT)
+ & TypedValue.COMPLEX_UNIT_MASK;
+ if (unit == TypedValue.COMPLEX_UNIT_FRACTION_PARENT) {
+ radiusType = RADIUS_TYPE_FRACTION_PARENT;
} else {
- radius = tv.getFloat();
- radiusType = RADIUS_TYPE_PIXELS;
+ radiusType = RADIUS_TYPE_FRACTION;
}
-
- st.mGradientRadius = radius;
- st.mGradientRadiusType = radiusType;
- } else if (st.mGradient == RADIAL_GRADIENT) {
- throw new XmlPullParserException(
- a.getPositionDescription()
- + "<gradient> tag requires 'gradientRadius' "
- + "attribute with radial type");
+ } else if (tv.type == TypedValue.TYPE_DIMENSION) {
+ radius = tv.getDimension(r.getDisplayMetrics());
+ radiusType = RADIUS_TYPE_PIXELS;
+ } else {
+ radius = tv.getFloat();
+ radiusType = RADIUS_TYPE_PIXELS;
}
+
+ st.mGradientRadius = radius;
+ st.mGradientRadiusType = radiusType;
}
}
diff --git a/keystore/tests/Android.bp b/keystore/tests/Android.bp
new file mode 100644
index 0000000..e9b22c1
--- /dev/null
+++ b/keystore/tests/Android.bp
@@ -0,0 +1,26 @@
+// 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.
+
+android_test {
+ name: "KeystoreTests",
+ // LOCAL_MODULE := keystore
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "hamcrest-library",
+ ],
+ platform_apis: true,
+ libs: ["android.test.runner"],
+ certificate: "platform",
+}
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
deleted file mode 100644
index 99d3197..0000000
--- a/keystore/tests/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# LOCAL_MODULE := keystore
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.test.rules hamcrest-library
-
-LOCAL_PACKAGE_NAME := KeystoreTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 66a5477..7b7599f 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -29,6 +29,7 @@
#include "androidfw/Asset.h"
#include "androidfw/Idmap.h"
+#include "androidfw/misc.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/Util.h"
@@ -39,8 +40,10 @@
static const std::string kResourcesArsc("resources.arsc");
-ApkAssets::ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path)
- : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path) {
+ApkAssets::ApkAssets(ZipArchiveHandle unmanaged_handle,
+ const std::string& path,
+ time_t last_mod_time)
+ : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path), last_mod_time_(last_mod_time) {
}
std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system) {
@@ -116,8 +119,10 @@
return {};
}
+ time_t last_mod_time = getFileModDate(path.c_str());
+
// Wrap the handle in a unique_ptr so it gets automatically closed.
- std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(unmanaged_handle, path));
+ std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(unmanaged_handle, path, last_mod_time));
// Find the resource table.
::ZipString entry_name(kResourcesArsc.c_str());
@@ -248,4 +253,8 @@
return result == -1;
}
+bool ApkAssets::IsUpToDate() const {
+ return last_mod_time_ == getFileModDate(path_.c_str());
+}
+
} // namespace android
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 35bbb58..49fc82b 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -84,6 +84,8 @@
return idmap_asset_.get() != nullptr;
}
+ bool IsUpToDate() const;
+
private:
DISALLOW_COPY_AND_ASSIGN(ApkAssets);
@@ -95,12 +97,13 @@
// Creates an Asset from any file on the file system.
static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
- ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path);
+ ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path, time_t last_mod_time);
using ZipArchivePtr = std::unique_ptr<ZipArchive, void(*)(ZipArchiveHandle)>;
ZipArchivePtr zip_handle_;
const std::string path_;
+ time_t last_mod_time_;
std::unique_ptr<Asset> resources_asset_;
std::unique_ptr<Asset> idmap_asset_;
std::unique_ptr<const LoadedArsc> loaded_arsc_;
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index fb60a96..89a9b99 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -84,6 +84,7 @@
}
CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
+ ATRACE_CALL();
if (!mRenderThread.getGrContext()) {
return CopyResult::UnknownError;
}
@@ -104,6 +105,7 @@
CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform,
const Rect& srcRect, SkBitmap* bitmap) {
+ ATRACE_CALL();
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
mRenderThread.requireGlContext();
} else {
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index ceab407..1b9e53b 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -19,6 +19,7 @@
#include "renderthread/VulkanManager.h"
#include "renderthread/RenderThread.h"
+#include <SkAndroidFrameworkUtils.h>
#include <GrBackendDrawableInfo.h>
#include <SkImage.h>
#include <utils/Color.h>
@@ -89,9 +90,29 @@
VkFunctorDrawable::~VkFunctorDrawable() {
}
-void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) {
- LOG_ALWAYS_FATAL("VkFunctorDrawable::onDraw() should never be called.");
- // Instead of calling onDraw(), the call should come from onSnapGpuDrawHandler.
+void VkFunctorDrawable::onDraw(SkCanvas* canvas) {
+ // "canvas" is either SkNWayCanvas created by SkiaPipeline::tryCapture (SKP capture use case) or
+ // AlphaFilterCanvas (used by RenderNodeDrawable to apply alpha in certain cases).
+ // "VkFunctorDrawable::onDraw" is not invoked for the most common case, when drawing in a GPU
+ // canvas.
+
+ if (canvas->getGrContext() == nullptr) {
+ // We're dumping a picture, render a light-blue rectangle instead
+ SkPaint paint;
+ paint.setColor(0xFF81D4FA);
+ canvas->drawRect(mBounds, paint);
+ } else {
+ // Handle the case when "canvas" is AlphaFilterCanvas. Find the wrapped GPU canvas.
+ SkCanvas* gpuCanvas = SkAndroidFrameworkUtils::getBaseWrappedCanvas(canvas);
+ // Enforce "canvas" must be an AlphaFilterCanvas. For GPU canvas, the call should come from
+ // onSnapGpuDrawHandler.
+ LOG_ALWAYS_FATAL_IF(
+ gpuCanvas == canvas,
+ "VkFunctorDrawable::onDraw() should not be called with a GPU canvas!");
+
+ // This will invoke onSnapGpuDrawHandler and regular draw flow.
+ gpuCanvas->drawDrawable(this);
+ }
}
std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDrawHandler(
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 1bcb819..16240b4 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -162,6 +162,7 @@
}
bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
+ ATRACE_NAME("TextureView#getBitmap");
auto& thread = RenderThread::getInstance();
return thread.queue().runSync([&]() -> bool {
return thread.readback().copyLayerInto(layer, &bitmap) == CopyResult::Success;
@@ -347,6 +348,7 @@
}
int RenderProxy::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {
+ ATRACE_NAME("HardwareBitmap readback");
RenderThread& thread = RenderThread::getInstance();
if (gettid() == thread.getTid()) {
// TODO: fix everything that hits this. We should never be triggering a readback ourselves.
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 1708d3c..3fed6b0 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -222,7 +222,17 @@
const SkISize maxSize = SkISize::Make(caps.maxImageExtent.width, caps.maxImageExtent.height);
ComputeWindowSizeAndTransform(&windowInfo, minSize, maxSize);
- windowInfo.bufferCount = std::max<uint32_t>(VulkanSurface::sMaxBufferCount, caps.minImageCount);
+ int query_value;
+ int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
+ if (err != 0 || query_value < 0) {
+ ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
+ query_value);
+ return nullptr;
+ }
+ auto min_undequeued_buffers = static_cast<uint32_t>(query_value);
+
+ windowInfo.bufferCount = min_undequeued_buffers
+ + std::max(VulkanSurface::sTargetBufferCount, caps.minImageCount);
if (caps.maxImageCount > 0 && windowInfo.bufferCount > caps.maxImageCount) {
// Application must settle for fewer images than desired:
windowInfo.bufferCount = caps.maxImageCount;
@@ -357,10 +367,9 @@
return false;
}
- // Lower layer insists that we have at least two buffers.
- err = native_window_set_buffer_count(window, std::max(2, windowInfo.bufferCount));
+ err = native_window_set_buffer_count(window, windowInfo.bufferCount);
if (err != 0) {
- ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%d) failed: %s (%d)",
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%zu) failed: %s (%d)",
windowInfo.bufferCount, strerror(-err), err);
return false;
}
@@ -392,7 +401,7 @@
}
void VulkanSurface::releaseBuffers() {
- for (uint32_t i = 0; i < VulkanSurface::sMaxBufferCount; i++) {
+ for (uint32_t i = 0; i < mWindowInfo.bufferCount; i++) {
VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index 418d40f..305483f 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -83,14 +83,19 @@
* as private to this class.
*
*/
- static constexpr int sMaxBufferCount = 3;
+
+ // How many buffers we want to be able to use ourselves. We want 1 in active rendering with
+ // 1 more queued, so 2. This will be added to NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, which is
+ // how many buffers the consumer needs (eg, 1 for SurfaceFlinger), getting to a typically
+ // triple-buffered queue as a result.
+ static constexpr uint32_t sTargetBufferCount = 2;
struct WindowInfo {
SkISize size;
PixelFormat pixelFormat;
android_dataspace dataspace;
int transform;
- int bufferCount;
+ size_t bufferCount;
uint64_t windowUsageFlags;
// size of the ANativeWindow if the inverse of transform requires us to swap width/height
@@ -111,7 +116,8 @@
const SkISize& maxSize);
void releaseBuffers();
- NativeBufferInfo mNativeBuffers[VulkanSurface::sMaxBufferCount];
+ // TODO: Just use a vector?
+ NativeBufferInfo mNativeBuffers[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
sp<ANativeWindow> mNativeWindow;
WindowInfo mWindowInfo;
diff --git a/location/Android.mk b/location/Android.mk
deleted file mode 100644
index 50509c6..0000000
--- a/location/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(call all-subdir-makefiles, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/location/tests/Android.bp b/location/tests/Android.bp
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/location/tests/Android.bp
@@ -0,0 +1 @@
+
diff --git a/location/tests/Android.mk b/location/tests/Android.mk
deleted file mode 100644
index 57848f3..0000000
--- a/location/tests/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/location/tests/locationtests/Android.bp b/location/tests/locationtests/Android.bp
new file mode 100644
index 0000000..1a4e2c7
--- /dev/null
+++ b/location/tests/locationtests/Android.bp
@@ -0,0 +1,19 @@
+android_test {
+ name: "FrameworksLocationTests",
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ platform_apis: true,
+ static_libs: [
+ "androidx.test.rules",
+ "core-test-rules",
+ "guava",
+ "mockito-target-minus-junit4",
+ "frameworks-base-testutils",
+ "truth-prebuilt",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/location/tests/locationtests/Android.mk b/location/tests/locationtests/Android.mk
deleted file mode 100644
index 3dcf694..0000000
--- a/location/tests/locationtests/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_PACKAGE_NAME := FrameworksLocationTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.test.rules \
- core-test-rules \
- guava \
- mockito-target-minus-junit4 \
- frameworks-base-testutils \
- truth-prebuilt \
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-include $(BUILD_PACKAGE)
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index e925731..a3eee0a 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -710,20 +710,7 @@
* @throws IllegalArgumentException if the argument is not a valid value.
*/
public @NonNull Builder setAllowedCapturePolicy(@CapturePolicy int capturePolicy) {
- switch (capturePolicy) {
- case ALLOW_CAPTURE_BY_NONE:
- mFlags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE;
- break;
- case ALLOW_CAPTURE_BY_SYSTEM:
- mFlags |= FLAG_NO_MEDIA_PROJECTION;
- mFlags &= ~FLAG_NO_SYSTEM_CAPTURE;
- break;
- case ALLOW_CAPTURE_BY_ALL:
- mFlags &= ~FLAG_NO_SYSTEM_CAPTURE & ~FLAG_NO_MEDIA_PROJECTION;
- break;
- default:
- throw new IllegalArgumentException("Unknown allow playback capture policy");
- }
+ mFlags = capturePolicyToFlags(capturePolicy, mFlags);
return this;
}
@@ -1219,6 +1206,24 @@
}
}
+ static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) {
+ switch (capturePolicy) {
+ case ALLOW_CAPTURE_BY_NONE:
+ flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE;
+ break;
+ case ALLOW_CAPTURE_BY_SYSTEM:
+ flags |= FLAG_NO_MEDIA_PROJECTION;
+ flags &= ~FLAG_NO_SYSTEM_CAPTURE;
+ break;
+ case ALLOW_CAPTURE_BY_ALL:
+ flags &= ~FLAG_NO_SYSTEM_CAPTURE & ~FLAG_NO_MEDIA_PROJECTION;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown allow playback capture policy");
+ }
+ return flags;
+ }
+
/** @hide */
@IntDef({
USAGE_UNKNOWN,
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7cb5e00..dc5c663 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1478,6 +1478,30 @@
}
}
+ /**
+ * Specifying if this audio may or may not be captured by other apps or the system.
+ *
+ * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
+ *
+ * Note that each audio track can also set its policy, in which case the most
+ * restrictive policy is always applied.
+ *
+ * @param capturePolicy one of
+ * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
+ * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
+ * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
+ * @throws IllegalArgumentException if the argument is not a valid value.
+ */
+ public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
+ int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0);
+ // TODO: got trough AudioService and save a cache to restore in case of AP crash
+ // TODO: also pass the package in case multiple packages have the same UID
+ int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags);
+ if (result != AudioSystem.AUDIO_STATUS_OK) {
+ Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
+ }
+ }
+
//====================================================================
// Offload query
/**
diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
index 9ee6f87..bcaef03 100644
--- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java
+++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
@@ -29,13 +29,17 @@
* Configuration for capturing audio played by other apps.
*
* Only the following audio can be captured:
- * - usage MUST be UNKNOWN or GAME or MEDIA. All other usages CAN NOT be capturable.
- * - audio attributes MUST NOT have the FLAG_NO_CAPTURE
+ * - usage MUST be {@link AudioAttributes#USAGE_UNKNOWN} or {@link AudioAttributes#USAGE_GAME}
+ * or {@link AudioAttributes#USAGE_MEDIA}. All other usages CAN NOT be captured.
+ * - audio attributes MUST have its ${@link AudioAttributes.Builder#setAllowedCapturePolicy}
+ * to {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
* - played by apps that MUST be in the same user profile as the capturing app
* (eg work profile can not capture user profile apps and vice-versa).
- * - played by apps that MUST NOT have in their manifest.xml the application
- * attribute android:allowAudioPlaybackCapture="false"
- * - played by apps that MUST have a targetSdkVersion higher or equal to 29 (Q).
+ * - played by apps for which the attribute allowAudioPlaybackCapture in their manifest
+ * MUST either be:
+ * * set to "true"
+ * * not set, and their targetSdkVersion MUST be equal or higher to
+ * {@link android.os.Build.VERSION_CODES#Q}.
*
* <p>An example for creating a capture configuration for capturing all media playback:
*
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index a7760a80..2dd7f0f 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -25,6 +25,7 @@
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
+import android.media.MediaRecorder.Source;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioPolicy;
import android.media.projection.MediaProjection;
@@ -539,7 +540,7 @@
* @return the same Builder instance.
* @throws IllegalArgumentException
*/
- public Builder setAudioSource(int source) throws IllegalArgumentException {
+ public Builder setAudioSource(@Source int source) throws IllegalArgumentException {
Preconditions.checkState(
mAudioPlaybackCaptureConfiguration == null,
ERROR_MESSAGE_SOURCE_MISMATCH);
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index ad255fe..d105fa3 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1022,6 +1022,11 @@
public static native float getStreamVolumeDB(int stream, int index, int device);
+ /**
+ * @see AudioManager#setAllowedCapturePolicy()
+ */
+ public static native int setAllowedCapturePolicy(int uid, int flags);
+
static boolean isOffloadSupported(@NonNull AudioFormat format, @NonNull AudioAttributes attr) {
return native_is_offload_supported(format.getEncoding(), format.getSampleRate(),
format.getChannelMask(), format.getChannelIndexMask(),
diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java
index e53b7e8..01a02f1 100644
--- a/media/java/android/media/HwAudioSource.java
+++ b/media/java/android/media/HwAudioSource.java
@@ -224,14 +224,4 @@
return new HwAudioSource(mAudioDeviceInfo, mAudioAttributes);
}
}
-
- /**
- * Eliminate {@link #deprecateStreamTypeForPlayback(int, String, String)} in API list.
- * TODO: remove this pseudo-override function
- * @hide
- */
- public static void deprecateStreamTypeForPlayback(int streamType, String className,
- String opName) throws IllegalArgumentException {
- // Do nothing.
- }
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 575a0bb..63b22df 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -18,6 +18,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.FloatRange;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -42,6 +43,8 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.RandomAccessFile;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -355,6 +358,22 @@
public static final int HOTWORD = 1999;
}
+ /** @hide */
+ @IntDef({
+ AudioSource.DEFAULT,
+ AudioSource.MIC,
+ AudioSource.VOICE_UPLINK,
+ AudioSource.VOICE_DOWNLINK,
+ AudioSource.VOICE_CALL,
+ AudioSource.CAMCORDER,
+ AudioSource.VOICE_RECOGNITION,
+ AudioSource.VOICE_COMMUNICATION,
+ AudioSource.UNPROCESSED,
+ AudioSource.VOICE_PERFORMANCE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Source {}
+
// TODO make AudioSource static (API change) and move this method inside the AudioSource class
/**
* @hide
@@ -547,11 +566,11 @@
* to be specified before setting recording-parameters or encoders. Call
* this only before setOutputFormat().
*
- * @param audio_source the audio source to use
+ * @param audioSource the audio source to use
* @throws IllegalStateException if it is called after setOutputFormat()
* @see android.media.MediaRecorder.AudioSource
*/
- public native void setAudioSource(int audio_source)
+ public native void setAudioSource(@Source int audioSource)
throws IllegalStateException;
/**
diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp
new file mode 100644
index 0000000..f0fbc50
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/Android.bp
@@ -0,0 +1,14 @@
+android_test {
+ name: "mediaframeworktest",
+ srcs: ["**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: [
+ "mockito-target-minus-junit4",
+ "androidx.test.rules",
+ "android-ex-camera2",
+ ],
+ platform_apis: true,
+}
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
deleted file mode 100644
index 167d255..0000000
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- mockito-target-minus-junit4 \
- androidx.test.rules \
- android-ex-camera2
-
-LOCAL_PACKAGE_NAME := mediaframeworktest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/MtpTests/Android.bp b/media/tests/MtpTests/Android.bp
new file mode 100644
index 0000000..7d2c7c6
--- /dev/null
+++ b/media/tests/MtpTests/Android.bp
@@ -0,0 +1,6 @@
+android_test {
+ name: "MtpTests",
+ srcs: ["**/*.java"],
+ static_libs: ["androidx.test.rules"],
+ platform_apis: true,
+}
diff --git a/media/tests/MtpTests/Android.mk b/media/tests/MtpTests/Android.mk
deleted file mode 100644
index 4cee62e..0000000
--- a/media/tests/MtpTests/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-
-LOCAL_PACKAGE_NAME := MtpTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index 76e2fe7..d409758 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -26,6 +26,7 @@
<uses-permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE" />
<uses-permission android:name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-sdk
android:targetSdkVersion="28"
@@ -78,6 +79,13 @@
</intent-filter>
</service>
+ <service android:name=".watchdog.ExplicitHealthCheckServiceImpl"
+ android:permission="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.watchdog.ExplicitHealthCheckService" />
+ </intent-filter>
+ </service>
+
<activity android:name=".notification.CopyCodeActivity"
android:exported="false"
android:theme="@android:style/Theme.NoDisplay"/>
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
new file mode 100644
index 0000000..040e2ab
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.ext.services.watchdog;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.service.watchdog.ExplicitHealthCheckService;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Routes explicit health check requests to the appropriate {@link ExplicitHealthChecker}.
+ */
+public final class ExplicitHealthCheckServiceImpl extends ExplicitHealthCheckService {
+ private static final String TAG = "ExplicitHealthCheckServiceImpl";
+ // TODO: Add build dependency on NetworkStack stable AIDL so we can stop hard coding class name
+ private static final String NETWORK_STACK_CONNECTOR_CLASS =
+ "android.net.INetworkStackConnector";
+ // Modified only #onCreate, using concurrent collection to ensure thread visibility
+ private final Map<String, ExplicitHealthChecker> mSupportedCheckers = new ConcurrentHashMap<>();
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ initHealthCheckers();
+ }
+
+ @Override
+ public void onRequestHealthCheck(String packageName) {
+ ExplicitHealthChecker checker = mSupportedCheckers.get(packageName);
+ if (checker != null) {
+ checker.request();
+ } else {
+ Log.w(TAG, "Ignoring request for explicit health check for unsupported package "
+ + packageName);
+ }
+ }
+
+ @Override
+ public void onCancelHealthCheck(String packageName) {
+ ExplicitHealthChecker checker = mSupportedCheckers.get(packageName);
+ if (checker != null) {
+ checker.cancel();
+ } else {
+ Log.w(TAG, "Ignoring request to cancel explicit health check for unsupported package "
+ + packageName);
+ }
+ }
+
+ @Override
+ public List<String> onGetSupportedPackages() {
+ return new ArrayList<>(mSupportedCheckers.keySet());
+ }
+
+ @Override
+ public List<String> onGetRequestedPackages() {
+ List<String> packages = new ArrayList<>();
+ Iterator<ExplicitHealthChecker> it = mSupportedCheckers.values().iterator();
+ // Could potentially race, where we read a checker#isPending and it changes before we
+ // return list. However, if it races and it is in the list, the caller might call #cancel
+ // which would fail, but that is fine. If it races and it ends up *not* in the list, it was
+ // already cancelled, so there's no need for the caller to cancel it
+ while (it.hasNext()) {
+ ExplicitHealthChecker checker = it.next();
+ if (checker.isPending()) {
+ packages.add(checker.getPackageName());
+ }
+ }
+ return packages;
+ }
+
+ private void initHealthCheckers() {
+ Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS);
+ ComponentName comp = intent.resolveSystemService(getPackageManager(), 0);
+ if (comp != null) {
+ String networkStackPackageName = comp.getPackageName();
+ mSupportedCheckers.put(networkStackPackageName,
+ new NetworkChecker(this, networkStackPackageName));
+ } else {
+ // On Go devices, or any device that does not ship the network stack module.
+ // The network stack will live in system_server process, so no need to monitor.
+ Log.i(TAG, "Network stack module not found");
+ }
+ }
+}
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java
new file mode 100644
index 0000000..650878e
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.ext.services.watchdog;
+
+/**
+ * A type of explicit health check that can be performed on a device, e.g network health check
+ */
+interface ExplicitHealthChecker {
+ /**
+ * Requests a checker to listen to explicit health checks for {@link #getPackageName}.
+ * {@link #isPending} will now return {@code true}.
+ */
+ void request();
+
+ /**
+ * Cancels a pending explicit health check request for {@link #getPackageName}.
+ * {@link #isPending} will now return {@code false}.
+ */
+ void cancel();
+
+ /**
+ * Returns {@code true} if a request is pending, {@code false} otherwise.
+ */
+ boolean isPending();
+
+ /**
+ * Returns the package name this checker can make requests for.
+ */
+ String getPackageName();
+}
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java b/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java
new file mode 100644
index 0000000..32375e6
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.ext.services.watchdog;
+
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.service.watchdog.ExplicitHealthCheckService;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Observes the network stack via the ConnectivityManager.
+ */
+final class NetworkChecker extends ConnectivityManager.NetworkCallback
+ implements ExplicitHealthChecker {
+ private static final String TAG = "NetworkChecker";
+
+ private final Object mLock = new Object();
+ private final ExplicitHealthCheckService mService;
+ private final String mPackageName;
+ @GuardedBy("mLock")
+ private boolean mIsPending;
+
+ NetworkChecker(ExplicitHealthCheckService service, String packageName) {
+ mService = service;
+ mPackageName = packageName;
+ }
+
+ @Override
+ public void request() {
+ synchronized (mLock) {
+ if (mIsPending) {
+ return;
+ }
+ mService.getSystemService(ConnectivityManager.class).registerNetworkCallback(
+ new NetworkRequest.Builder().build(), this);
+ mIsPending = true;
+ }
+ }
+
+ @Override
+ public void cancel() {
+ synchronized (mLock) {
+ if (!mIsPending) {
+ return;
+ }
+ mService.getSystemService(ConnectivityManager.class).unregisterNetworkCallback(this);
+ mIsPending = false;
+ }
+ }
+
+ @Override
+ public boolean isPending() {
+ synchronized (mLock) {
+ return mIsPending;
+ }
+ }
+
+ @Override
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ // TODO(b/120598832): Also monitor NetworkCallback#onAvailable to see if we have any
+ // available networks that may be unusable. This could be additional signal to our heuristics
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities capabilities) {
+ synchronized (mLock) {
+ if (mIsPending
+ && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
+ mService.notifyHealthCheckPassed(mPackageName);
+ cancel();
+ }
+ }
+ }
+}
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index b0a7923..9b60dc3 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -20,6 +20,17 @@
package="com.android.networkstack"
android:sharedUserId="android.uid.networkstack">
<uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <!-- Send latency broadcast as current user -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+
<!-- Signature permission defined in NetworkStackStub -->
<uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
<application>
diff --git a/packages/NetworkStack/AndroidManifestBase.xml b/packages/NetworkStack/AndroidManifestBase.xml
index f69e4b2..69a4da4 100644
--- a/packages/NetworkStack/AndroidManifestBase.xml
+++ b/packages/NetworkStack/AndroidManifestBase.xml
@@ -20,15 +20,6 @@
package="com.android.networkstack"
android:versionCode="11"
android:versionName="Q-initial">
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
- <!-- Send latency broadcast as current user -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<application
android:label="NetworkStack"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
index 3dd90ee..d2f3259 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -74,6 +74,7 @@
import java.net.UnknownHostException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
@@ -282,6 +283,7 @@
private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
// TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
+ private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
// Endianness is not an issue for this constant because the APF interpreter always operates in
// network byte order.
@@ -881,10 +883,23 @@
protected final TcpKeepaliveAckData mPacket;
protected final byte[] mSrcDstAddr;
+ protected final byte[] mPortSeqAckFingerprint;
TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) {
mPacket = packet;
mSrcDstAddr = srcDstAddr;
+ mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort,
+ mPacket.dstPort, mPacket.seq, mPacket.ack);
+ }
+
+ static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) {
+ final ByteBuffer fp = ByteBuffer.allocate(12);
+ fp.order(ByteOrder.BIG_ENDIAN);
+ fp.putShort((short) srcPort);
+ fp.putShort((short) dstPort);
+ fp.putInt(seq);
+ fp.putInt(ack);
+ return fp.array();
}
static byte[] concatArrays(final byte[]... arr) {
@@ -919,10 +934,6 @@
private class TcpKeepaliveAckV4 extends TcpKeepaliveAck {
private static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
- private static final int IPV4_TCP_SRC_PORT_OFFSET = 0;
- private static final int IPV4_TCP_DST_PORT_OFFSET = 2;
- private static final int IPV4_TCP_SEQ_OFFSET = 4;
- private static final int IPV4_TCP_ACK_OFFSET = 8;
TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
this(new TcpKeepaliveAckData(sentKeepalivePacket));
@@ -934,12 +945,12 @@
@Override
void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
final String nextFilterLabel = "keepalive_ack" + getUniqueNumberLocked();
- gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
- gen.addJumpIfR0NotEquals(IPPROTO_TCP, nextFilterLabel);
+
gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
- // Pass the packet if it's not zero-sized :
+ // Skip to the next filter if it's not zero-sized :
+ // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0
// Load the IP header size into R1
gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
// Load the TCP header size into R0 (it's indexed by R1)
@@ -947,27 +958,18 @@
// Size offset is in the top nibble, but it must be multiplied by 4, and the two
// top bits of the low nibble are guaranteed to be zeroes. Right-shift R0 by 2.
gen.addRightShift(2);
- // R0 += R1 -> R0 contains TCP + IP headers lenght
+ // R0 += R1 -> R0 contains TCP + IP headers length
gen.addAddR1();
- // Add the Ethernet header length to R0.
- gen.addLoadImmediate(Register.R1, ETH_HEADER_LEN);
- gen.addAddR1();
- // Compare total length of headers to the size of the packet.
- gen.addLoadFromMemory(Register.R1, gen.PACKET_SIZE_MEMORY_SLOT);
+ // Load IPv4 total length
+ gen.addLoad16(Register.R1, IPV4_TOTAL_LENGTH_OFFSET);
gen.addNeg(Register.R0);
gen.addAddR1();
gen.addJumpIfR0NotEquals(0, nextFilterLabel);
-
// Add IPv4 header length
gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
- gen.addLoad16Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_SRC_PORT_OFFSET);
- gen.addJumpIfR0NotEquals(mPacket.srcPort, nextFilterLabel);
- gen.addLoad16Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_DST_PORT_OFFSET);
- gen.addJumpIfR0NotEquals(mPacket.dstPort, nextFilterLabel);
- gen.addLoad32Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_SEQ_OFFSET);
- gen.addJumpIfR0NotEquals(mPacket.seq, nextFilterLabel);
- gen.addLoad32Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_ACK_OFFSET);
- gen.addJumpIfR0NotEquals(mPacket.ack, nextFilterLabel);
+ gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN);
+ gen.addAddR1();
+ gen.addJumpIfBytesNotEqual(Register.R0, mPortSeqAckFingerprint, nextFilterLabel);
maybeSetupCounter(gen, Counter.DROPPED_IPV4_KEEPALIVE_ACK);
gen.addJump(mCountAndDropLabel);
@@ -1169,9 +1171,10 @@
gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
}
- // If any keepalive filters,
- generateKeepaliveFilter(gen);
+ // If any keepalive filter matches, drop
+ generateV4KeepaliveFilters(gen);
+ // Otherwise, this is an IPv4 unicast, pass
// If L2 broadcast packet, drop.
// TODO: can we invert this condition to fall through to the common pass case below?
maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
@@ -1180,7 +1183,7 @@
maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
gen.addJump(mCountAndDropLabel);
} else {
- generateKeepaliveFilter(gen);
+ generateV4KeepaliveFilters(gen);
}
// Otherwise, pass
@@ -1188,12 +1191,25 @@
gen.addJump(mCountAndPassLabel);
}
- private void generateKeepaliveFilter(ApfGenerator gen) throws IllegalInstructionException {
+ private void generateV4KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
+ final String skipV4KeepaliveFilter = "skip_v4_keepalive_filter";
+ final boolean haveV4KeepaliveAcks = NetworkStackUtils.any(mKeepaliveAcks,
+ ack -> ack instanceof TcpKeepaliveAckV4);
+
+ // If no keepalive acks
+ if (!haveV4KeepaliveAcks) return;
+
+ // If not tcp, skip keepalive filters
+ gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
+ gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipV4KeepaliveFilter);
+
// Drop IPv4 Keepalive acks
for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
final TcpKeepaliveAck ack = mKeepaliveAcks.valueAt(i);
if (ack instanceof TcpKeepaliveAckV4) ack.generateFilterLocked(gen);
}
+
+ gen.defineLabel(skipV4KeepaliveFilter);
}
/**
@@ -1244,11 +1260,14 @@
maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
+ // If any keepalive filter matches, drop
+ generateV6KeepaliveFilters(gen);
// Not multicast. Pass.
maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
gen.addJump(mCountAndPassLabel);
gen.defineLabel(skipIPv6MulticastFilterLabel);
} else {
+ generateV6KeepaliveFilters(gen);
// If not ICMPv6, pass.
maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
@@ -1272,12 +1291,27 @@
maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
gen.addJump(mCountAndDropLabel);
gen.defineLabel(skipUnsolicitedMulticastNALabel);
+ }
+
+ private void generateV6KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
+ final String skipV6KeepaliveFilter = "skip_v6_keepalive_filter";
+ final boolean haveV6KeepaliveAcks = NetworkStackUtils.any(mKeepaliveAcks,
+ ack -> ack instanceof TcpKeepaliveAckV6);
+
+ // If no keepalive acks
+ if (!haveV6KeepaliveAcks) return;
+
+ // If not tcp, skip keepalive filters
+ gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
+ gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipV6KeepaliveFilter);
// Drop IPv6 Keepalive acks
for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
final TcpKeepaliveAck ack = mKeepaliveAcks.valueAt(i);
if (ack instanceof TcpKeepaliveAckV6) ack.generateFilterLocked(gen);
}
+
+ gen.defineLabel(skipV6KeepaliveFilter);
}
/**
@@ -1294,6 +1328,8 @@
* <li>Pass all non-IPv4 and non-IPv6 packets,
* <li>Drop IPv6 ICMPv6 NAs to ff02::1.
* <li>Drop IPv6 ICMPv6 RSs.
+ * <li>Filter IPv4 packets (see generateIPv4FilterLocked())
+ * <li>Filter IPv6 packets (see generateIPv6FilterLocked())
* <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
* insertion of RA filters here, or if there aren't any, just passes the packets.
* </ul>
@@ -1737,7 +1773,7 @@
}
pw.decreaseIndent();
- pw.println("Keepalive filter:");
+ pw.println("Keepalive filters:");
pw.increaseIndent();
for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
final TcpKeepaliveAck keepaliveAck = mKeepaliveAcks.valueAt(i);
diff --git a/packages/NetworkStack/src/android/net/apf/ApfGenerator.java b/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
index 809327a..44ce2db 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
@@ -108,7 +108,7 @@
private String mLabel;
// When mOpcode == Opcodes.JNEBS:
private byte[] mCompareBytes;
- // Offset in bytes from the begining of this program. Set by {@link ApfGenerator#generate}.
+ // Offset in bytes from the beginning of this program. Set by {@link ApfGenerator#generate}.
int offset;
Instruction(Opcodes opcode, Register register) {
@@ -431,7 +431,7 @@
/**
* Add an instruction to the end of the program to load the byte at offset {@code offset}
- * bytes from the begining of the packet into {@code register}.
+ * bytes from the beginning of the packet into {@code register}.
*/
public ApfGenerator addLoad8(Register register, int offset) {
Instruction instruction = new Instruction(Opcodes.LDB, register);
@@ -442,7 +442,7 @@
/**
* Add an instruction to the end of the program to load 16-bits at offset {@code offset}
- * bytes from the begining of the packet into {@code register}.
+ * bytes from the beginning of the packet into {@code register}.
*/
public ApfGenerator addLoad16(Register register, int offset) {
Instruction instruction = new Instruction(Opcodes.LDH, register);
@@ -453,7 +453,7 @@
/**
* Add an instruction to the end of the program to load 32-bits at offset {@code offset}
- * bytes from the begining of the packet into {@code register}.
+ * bytes from the beginning of the packet into {@code register}.
*/
public ApfGenerator addLoad32(Register register, int offset) {
Instruction instruction = new Instruction(Opcodes.LDW, register);
@@ -464,7 +464,7 @@
/**
* Add an instruction to the end of the program to load a byte from the packet into
- * {@code register}. The offset of the loaded byte from the begining of the packet is
+ * {@code register}. The offset of the loaded byte from the beginning of the packet is
* the sum of {@code offset} and the value in register R1.
*/
public ApfGenerator addLoad8Indexed(Register register, int offset) {
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index 481dbda..fedb8d1 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -17,10 +17,13 @@
package android.net.util;
import android.annotation.NonNull;
+import android.util.SparseArray;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.List;
+import java.util.function.Predicate;
+
/**
* Collection of utilities for the network stack.
@@ -65,4 +68,17 @@
}
return array;
}
+
+ /**
+ * @return True if there exists at least one element in the sparse array for which
+ * condition {@code predicate}
+ */
+ public static <T> boolean any(SparseArray<T> array, Predicate<T> predicate) {
+ for (int i = 0; i < array.size(); ++i) {
+ if (predicate.test(array.valueAt(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp
index aadf99e..0535af3 100644
--- a/packages/NetworkStack/tests/Android.bp
+++ b/packages/NetworkStack/tests/Android.bp
@@ -45,6 +45,8 @@
"libcrypto",
"libcutils",
"libdexfile",
+ "ld-android",
+ "libdl_android",
"libhidl-gen-utils",
"libhidlbase",
"libhidltransport",
diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
index 88a05d5..a0e508f 100644
--- a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
+++ b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
@@ -1006,7 +1006,7 @@
private static final int IPV4_HEADER_LEN = 20;
private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
- private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
+ private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12;
private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
diff --git a/packages/OsuLogin/res/values/strings.xml b/packages/OsuLogin/res/values/strings.xml
index 06fa8c7..14de0f5 100644
--- a/packages/OsuLogin/res/values/strings.xml
+++ b/packages/OsuLogin/res/values/strings.xml
@@ -3,4 +3,6 @@
<string name="app_name">OsuLogin</string>
<!-- action bar label [CHAR LIMIT=32] -->
<string name="action_bar_label">Online Sign Up</string>
+ <!-- toast message [CHAR LIMIT=32] -->
+ <string name="sign_up_failed">Sign-up failed</string>
</resources>
diff --git a/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java b/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java
index 82e33cc..416894b 100644
--- a/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java
+++ b/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java
@@ -38,6 +38,7 @@
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
+import android.widget.Toast;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
@@ -141,6 +142,7 @@
Log.d(TAG, "Lost for the current Network, close the browser");
}
mForceDisconnect = false; // It is already disconnected.
+ showSignUpFailedToast();
if (mNetwork.equals(network)) {
finishAndRemoveTask();
}
@@ -229,6 +231,11 @@
return "";
}
+ private void showSignUpFailedToast() {
+ Toast.makeText(getApplicationContext(), R.string.sign_up_failed,
+ Toast.LENGTH_SHORT).show();
+ }
+
private class OsuWebViewClient extends WebViewClient {
boolean mPageError = false;
boolean mRedirectResponseReceived = false;
diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp
new file mode 100644
index 0000000..9420954
--- /dev/null
+++ b/packages/PackageInstaller/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_app {
+ name: "PackageInstaller",
+
+ srcs: ["src/**/*.java"],
+
+ certificate: "platform",
+ privileged: true,
+ platform_apis: true,
+
+ static_libs: [
+ "xz-java",
+ "androidx.leanback_leanback",
+ ],
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 441dbac..bde1b25 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -26,6 +26,7 @@
import android.app.AppOpsManager;
import android.app.Dialog;
import android.app.DialogFragment;
+import android.app.admin.DevicePolicyManager;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
@@ -427,7 +428,7 @@
if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
initiateInstall();
} else {
- // Check for unknown sources restriction
+ // Check for unknown sources restrictions.
final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle());
final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource(
@@ -436,16 +437,28 @@
& (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
if (systemRestriction != 0) {
showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
- } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET
- || unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
- startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
- finish();
+ } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
+ startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+ } else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
+ startAdminSupportDetailsActivity(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
} else {
handleUnknownSources();
}
}
}
+ private void startAdminSupportDetailsActivity(String restriction) {
+ // If the given restriction is set by an admin, display information about the
+ // admin enforcing the restriction for the affected user.
+ final DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
+ final Intent showAdminSupportDetailsIntent = dpm.createAdminSupportIntent(restriction);
+ if (showAdminSupportDetailsIntent != null) {
+ startActivity(showAdminSupportDetailsIntent);
+ }
+ finish();
+ }
+
private void handleUnknownSources() {
if (mOriginatingPackage == null) {
Log.i(TAG, "No source found for package " + mPkgInfo.packageName);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index fdc0fd3..5f2bc4e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -84,7 +84,7 @@
private static final long DEFAULT_MAX_CACHED_SCORE_AGE_MILLIS = 20 * DateUtils.MINUTE_IN_MILLIS;
/** Maximum age of scan results to hold onto while actively scanning. **/
- private static final long MAX_SCAN_RESULT_AGE_MILLIS = 15000;
+ @VisibleForTesting static final long MAX_SCAN_RESULT_AGE_MILLIS = 15000;
private static final String TAG = "WifiTracker";
private static final boolean DBG() {
@@ -142,6 +142,13 @@
*/
private boolean mStaleScanResults = true;
+ /**
+ * Tracks whether the latest SCAN_RESULTS_AVAILABLE_ACTION contained new scans. If not, then
+ * we treat the last scan as an aborted scan and increase the eviction timeout window to avoid
+ * completely flushing the AP list before the next successful scan completes.
+ */
+ private boolean mLastScanSucceeded = true;
+
// Does not need to be locked as it only updated on the worker thread, with the exception of
// during onStart, which occurs before the receiver is registered on the work handler.
private final HashMap<String, ScanResult> mScanResultCache = new HashMap<>();
@@ -478,17 +485,22 @@
}
/**
- * Remove old scan results from the cache.
+ * Remove old scan results from the cache. If {@link #mLastScanSucceeded} is false, then
+ * increase the timeout window to avoid completely flushing the AP list before the next
+ * successful scan completes.
*
* <p>Should only ever be invoked from {@link #updateScanResultCache(List)} when
* {@link #mStaleScanResults} is false.
*/
private void evictOldScans() {
+ long evictionTimeoutMillis = mLastScanSucceeded ? MAX_SCAN_RESULT_AGE_MILLIS
+ : MAX_SCAN_RESULT_AGE_MILLIS * 2;
+
long nowMs = SystemClock.elapsedRealtime();
for (Iterator<ScanResult> iter = mScanResultCache.values().iterator(); iter.hasNext(); ) {
ScanResult result = iter.next();
// result timestamp is in microseconds
- if (nowMs - result.timestamp / 1000 > MAX_SCAN_RESULT_AGE_MILLIS) {
+ if (nowMs - result.timestamp / 1000 > evictionTimeoutMillis) {
iter.remove();
}
}
@@ -840,6 +852,8 @@
WifiManager.WIFI_STATE_UNKNOWN));
} else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
mStaleScanResults = false;
+ mLastScanSucceeded =
+ intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, true);
fetchScansAndConfigsAndUpdateAccessPoints();
} else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index edf414d..683ec8b 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -270,7 +270,7 @@
SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
}
- private static ScanResult buildStaleScanResult() {
+ private static ScanResult buildScanResultWithTimestamp(long timestampMillis) {
return new ScanResult(
WifiSsid.createFromAsciiEncoded(SSID_3),
BSSID_3,
@@ -280,7 +280,7 @@
"", // capabilities
RSSI_3,
0, // frequency
- 0 /* microsecond timestamp */);
+ timestampMillis * 1000 /* microsecond timestamp */);
}
private static WifiConfiguration buildPasspointConfiguration(String fqdn, String friendlyName) {
@@ -379,6 +379,12 @@
tracker.mReceiver.onReceive(mContext, i);
}
+ private void sendFailedScanResults(WifiTracker tracker) throws InterruptedException {
+ Intent i = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ i.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
+ tracker.mReceiver.onReceive(mContext, i);
+ }
+
private void sendUpdatedScores() throws InterruptedException {
Bundle attr1 = new Bundle();
attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve1);
@@ -982,8 +988,8 @@
@Test
public void onStart_updateScanResults_evictOldScanResult() {
- when(mockWifiManager.getScanResults()).thenReturn(
- Arrays.asList(buildScanResult1(), buildScanResult2(), buildStaleScanResult()));
+ when(mockWifiManager.getScanResults()).thenReturn(Arrays.asList(
+ buildScanResult1(), buildScanResult2(), buildScanResultWithTimestamp(0)));
WifiTracker tracker = createMockedWifiTracker();
tracker.forceUpdate();
@@ -995,6 +1001,33 @@
}
/**
+ * Verifies that a failed scan reported on SCAN_RESULTS_AVAILABLE_ACTION should increase the
+ * ScanResult eviction timeout to twice the default.
+ */
+ @Test
+ public void failedScan_increasesEvictionTimeout() throws InterruptedException {
+ when(mockWifiManager.getScanResults()).thenReturn(Arrays.asList(
+ buildScanResult1(), buildScanResult2(), buildScanResultWithTimestamp(
+ SystemClock.elapsedRealtime() - WifiTracker.MAX_SCAN_RESULT_AGE_MILLIS)));
+ WifiTracker tracker = createMockedWifiTracker();
+
+ sendFailedScanResults(tracker);
+
+ // Failed scan increases timeout window to include the stale scan
+ assertThat(tracker.getAccessPoints()).hasSize(3);
+ assertThat(tracker.getAccessPoints().get(0).getBssid()).isEqualTo(BSSID_1);
+ assertThat(tracker.getAccessPoints().get(1).getBssid()).isEqualTo(BSSID_2);
+ assertThat(tracker.getAccessPoints().get(2).getBssid()).isEqualTo(BSSID_3);
+
+ sendScanResults(tracker);
+
+ // Successful scan resets the timeout window to remove the stale scan
+ assertThat(tracker.getAccessPoints()).hasSize(2);
+ assertThat(tracker.getAccessPoints().get(0).getBssid()).isEqualTo(BSSID_1);
+ assertThat(tracker.getAccessPoints().get(1).getBssid()).isEqualTo(BSSID_2);
+ }
+
+ /**
* Verifies that updatePasspointAccessPoints will only return AccessPoints whose
* isPasspoint() evaluates as true.
*/
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 4b342b3..296f7a1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -16,6 +16,7 @@
package com.android.providers.settings;
+import static android.os.Process.INVALID_UID;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
@@ -2777,7 +2778,7 @@
boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
- setting.getPackageName())) {
+ setting.getPackageName(), INVALID_UID, userId)) {
if (prefix != null && !setting.getName().startsWith(prefix)) {
continue;
}
@@ -2797,7 +2798,7 @@
boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
- setting.getPackageName())) {
+ setting.getPackageName(), INVALID_UID, userId)) {
if (prefix != null && !setting.getName().startsWith(prefix)) {
continue;
}
@@ -4410,7 +4411,7 @@
}
try {
final boolean systemSet = SettingsState.isSystemPackage(getContext(),
- setting.getPackageName(), callingUid);
+ setting.getPackageName(), callingUid, userId);
if (systemSet) {
settings.insertSettingLocked(name, setting.getValue(),
setting.getTag(), true, setting.getPackageName());
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 521163f..c05c4cd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -17,6 +17,7 @@
package com.android.providers.settings;
import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.Process.INVALID_UID;
import android.annotation.NonNull;
import android.content.Context;
@@ -1124,11 +1125,16 @@
return sb.toString();
}
+ // Check if a specific package belonging to the caller is part of the system package.
public static boolean isSystemPackage(Context context, String packageName) {
- return isSystemPackage(context, packageName, Binder.getCallingUid());
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ return isSystemPackage(context, packageName, callingUid, callingUserId);
}
- public static boolean isSystemPackage(Context context, String packageName, int callingUid) {
+ // Check if a specific package, uid, and user ID are part of the system package.
+ public static boolean isSystemPackage(Context context, String packageName, int uid,
+ int userId) {
synchronized (sLock) {
if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
return true;
@@ -1140,26 +1146,19 @@
return false;
}
- // Native services running as a special UID get a pass
- final int callingAppId = UserHandle.getAppId(callingUid);
- if (callingAppId < FIRST_APPLICATION_UID) {
- sSystemUids.put(callingAppId, callingAppId);
- return true;
+ if (uid != INVALID_UID) {
+ // Native services running as a special UID get a pass
+ final int callingAppId = UserHandle.getAppId(uid);
+ if (callingAppId < FIRST_APPLICATION_UID) {
+ sSystemUids.put(callingAppId, callingAppId);
+ return true;
+ }
}
- // While some callers may have permissions to manipulate cross user
- // settings or some settings are stored in the parent of a managed
- // profile for the purpose of determining whether the other end is a
- // system component we need to use the user id of the caller for
- // pulling information about the caller from the package manager.
- final int callingUserId = UserHandle.getUserId(callingUid);
-
final long identity = Binder.clearCallingIdentity();
try {
- final int uid;
try {
- uid = context.getPackageManager().getPackageUidAsUser(packageName, 0,
- callingUserId);
+ uid = context.getPackageManager().getPackageUidAsUser(packageName, 0, userId);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
@@ -1187,7 +1186,7 @@
PackageInfo packageInfo;
try {
packageInfo = context.getPackageManager().getPackageInfoAsUser(
- packageName, PackageManager.GET_SIGNATURES, callingUserId);
+ packageName, PackageManager.GET_SIGNATURES, userId);
if ((packageInfo.applicationInfo.flags
& ApplicationInfo.FLAG_PERSISTENT) != 0
&& (packageInfo.applicationInfo.flags
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d6e61eb..d39646b 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -125,6 +125,8 @@
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+ <!-- Shell only holds android.permission.NETWORK_SCAN in order to to enable CTS testing -->
+ <uses-permission android:name="android.permission.NETWORK_SCAN" />
<uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
<uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
<uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
@@ -178,6 +180,8 @@
<!-- Permission needed to run network tests in CTS -->
<uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
+ <!-- Permission needed to test tcp keepalive offload. -->
+ <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
<!-- Permission needed to run keyguard manager tests in CTS -->
<uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk
index b93ddde..44ff338 100644
--- a/packages/Shell/tests/Android.mk
+++ b/packages/Shell/tests/Android.mk
@@ -9,7 +9,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test \
+ androidx.test.rules \
mockito-target-minus-junit4 \
ub-uiautomator \
junit \
diff --git a/packages/Shell/tests/AndroidManifest.xml b/packages/Shell/tests/AndroidManifest.xml
index 6d564c6..e845ef9 100644
--- a/packages/Shell/tests/AndroidManifest.xml
+++ b/packages/Shell/tests/AndroidManifest.xml
@@ -36,7 +36,7 @@
</activity>
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.shell"
android:label="Tests for Shell" />
diff --git a/packages/Shell/tests/AndroidTest.xml b/packages/Shell/tests/AndroidTest.xml
index e592d82..e03b68a 100644
--- a/packages/Shell/tests/AndroidTest.xml
+++ b/packages/Shell/tests/AndroidTest.xml
@@ -22,7 +22,7 @@
<option name="test-tag" value="ShellTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.shell.tests" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportProgressServiceTest.java b/packages/Shell/tests/src/com/android/shell/BugreportProgressServiceTest.java
index cef74ae..433eca2 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportProgressServiceTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportProgressServiceTest.java
@@ -20,7 +20,6 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
-import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
@@ -29,12 +28,12 @@
import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContext;
import android.util.Pair;
-import org.junit.Before;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index e69b0a8..3a71632 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -42,6 +42,40 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningServiceInfo;
+import android.app.Instrumentation;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.service.notification.StatusBarNotification;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
+
+import libcore.io.Streams;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
@@ -60,40 +94,6 @@
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
-import libcore.io.Streams;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.runner.RunWith;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningServiceInfo;
-import android.app.Instrumentation;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
-
/**
* Integration tests for {@link BugreportReceiver}.
* <p>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index 7b7657a..105be46 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -28,7 +28,7 @@
public interface ClockPlugin extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_CLOCK";
- int VERSION = 2;
+ int VERSION = 3;
/**
* Get the name of the clock face.
@@ -48,6 +48,17 @@
Bitmap getThumbnail();
/**
+ * Get preview images of clock face to be shown in the picker app.
+ *
+ * Preview image should be realistic and show what the clock face will look like on AOD and lock
+ * screen.
+ *
+ * @param width width of the preview image, should be the same as device width in pixels.
+ * @param height height of the preview image, should be the same as device height in pixels.
+ */
+ Bitmap getPreview(int width, int height);
+
+ /**
* Get clock view.
* @return clock view from plugin.
*/
diff --git a/packages/SystemUI/res/drawable/ic_alarm.xml b/packages/SystemUI/res/drawable/ic_alarm.xml
new file mode 100644
index 0000000..1c1adcd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_alarm.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="17dp"
+ android:width="17dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M13,8h-2v5.41l3.79,3.8 1.42,-1.42 -3.21,-3.2zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7zM16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM2.056,5.654L6.663,1.81l1.28,1.536L3.338,7.19z"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_alarm_dim.xml b/packages/SystemUI/res/drawable/ic_alarm_dim.xml
new file mode 100644
index 0000000..37ab873
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_alarm_dim.xml
@@ -0,0 +1,26 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="17dp"
+ android:width="17dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillAlpha="0.3"
+ android:pathData="M13,8h-2v5.41l3.79,3.8 1.42,-1.42 -3.21,-3.2zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7zM16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM2.056,5.654L6.663,1.81l1.28,1.536L3.338,7.19z"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_bluetooth_connected.xml b/packages/SystemUI/res/drawable/ic_bluetooth_connected.xml
new file mode 100644
index 0000000..125082c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_bluetooth_connected.xml
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_cast.xml b/packages/SystemUI/res/drawable/ic_cast.xml
new file mode 100644
index 0000000..a2c2eb2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_cast.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM1,14v2c2.76,0 5,2.24 5,5h2c0,-3.87 -3.13,-7 -7,-7zM1,10v2c4.97,0 9,4.03 9,9h2c0,-6.08 -4.93,-11 -11,-11z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_cast_connected.xml b/packages/SystemUI/res/drawable/ic_cast_connected.xml
new file mode 100644
index 0000000..995fd49
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_cast_connected.xml
@@ -0,0 +1,26 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M1,18v3h3C4,19.34 2.66,18 1,18zM1,14v2c2.76,0 5,2.24 5,5h2C8,17.13 4.87,14 1,14zM19,7H5v1.63c3.96,1.28 7.09,4.41 8.37,8.37H19V7zM1,10v2c4.97,0 9,4.03 9,9h2C12,14.92 7.07,10 1,10zM21,3H3C1.9,3 1,3.9 1,5v3h2V5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2V5C23,3.9 22.1,3 21,3"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_saver.xml b/packages/SystemUI/res/drawable/ic_data_saver.xml
index 0f027ee..cc3f539 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver.xml
@@ -14,15 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="18dp"
+ android:height="18dp"
android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
+ android:viewportHeight="24.0">
<path
- android:pathData="M16,12c0,0.55 -0.45,1 -1,1h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2L9,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2L11,9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1zM17.69,16.87a7.437,7.437 0,0 1,-5.93 2.63c-3.82,-0.12 -7.03,-3.25 -7.25,-7.07 -0.21,-3.84 2.48,-7.1 6.07,-7.79 0.24,-0.04 0.42,-0.24 0.42,-0.48L11,2.62c0,-0.3 -0.27,-0.55 -0.57,-0.5A10.02,10.02 0,0 0,2.09 13.4c0.59,4.4 4.16,7.94 8.56,8.52a9.99,9.99 0,0 0,9.14 -3.65,0.5 0.5,0 0,0 -0.15,-0.74l-1.32,-0.76a0.469,0.469 0,0 0,-0.63 0.1z"
+ android:pathData="M11,8v3L8,11v2h3v3h2v-3h3v-2h-3L13,8zM13,2.05v3.03c3.39,0.49 6,3.39 6,6.92 0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53c0.56,-1.24 0.88,-2.62 0.88,-4.07 0,-5.18 -3.95,-9.45 -9,-9.95zM12,19c-3.87,0 -7,-3.13 -7,-7 0,-3.53 2.61,-6.43 6,-6.92L11,2.05c-5.06,0.5 -9,4.76 -9,9.95 0,5.52 4.47,10 9.99,10 3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z"
android:fillColor="#FFFFFFFF"/>
- <path
- android:pathData="M13.41,4.64a0.493,0.493 0,0 1,-0.41 -0.48L13,2.62c0,-0.3 0.27,-0.55 0.57,-0.5C18.35,2.88 22,7.01 22,12c0,1.23 -0.23,2.41 -0.64,3.5 -0.11,0.28 -0.45,0.4 -0.72,0.24l-1.33,-0.77a0.484,0.484 0,0 1,-0.21 -0.59c0.25,-0.75 0.39,-1.55 0.39,-2.38 0.01,-3.65 -2.62,-6.69 -6.08,-7.36z"
- android:fillColor="#54FFFFFF" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_saver_off.xml b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
index 29e6c91..d8e9bc4 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver_off.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
@@ -17,9 +17,8 @@
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
+ android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M18.32,16.75l1.32,0.76c0.26,0.15 0.34,0.51 0.15,0.74 -2.09,2.6 -5.44,4.14 -9.14,3.65 -4.4,-0.58 -7.96,-4.12 -8.56,-8.52C1.34,7.8 5.21,2.95 10.43,2.12c0.3,-0.05 0.57,0.2 0.57,0.5v1.53c0,0.24 -0.18,0.44 -0.41,0.49 -3.6,0.69 -6.29,3.95 -6.07,7.79 0.21,3.82 3.43,6.95 7.25,7.07 2.37,0.08 4.51,-0.96 5.93,-2.63a0.48,0.48 0,0 1,0.62 -0.12zM19.5,12c0,0.83 -0.14,1.63 -0.39,2.38 -0.08,0.23 0.01,0.47 0.21,0.59l1.33,0.77c0.26,0.15 0.61,0.04 0.72,-0.24 0.4,-1.09 0.63,-2.27 0.63,-3.5 0,-4.99 -3.65,-9.12 -8.43,-9.88 -0.3,-0.04 -0.57,0.2 -0.57,0.5v1.53c0,0.24 0.18,0.44 0.41,0.48 3.46,0.68 6.09,3.72 6.09,7.37z" />
+ android:pathData="M13,2.05v3.03c3.39,0.49 6,3.39 6,6.92 0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53c0.56,-1.24 0.88,-2.62 0.88,-4.07 0,-5.18 -3.95,-9.45 -9,-9.95zM12,19c-3.87,0 -7,-3.13 -7,-7 0,-3.53 2.61,-6.43 6,-6.92V2.05c-5.06,0.5 -9,4.76 -9,9.95 0,5.52 4.47,10 9.99,10 3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_dnd.xml b/packages/SystemUI/res/drawable/ic_dnd.xml
deleted file mode 100644
index 09a6aab..0000000
--- a/packages/SystemUI/res/drawable/ic_dnd.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="24dp"
- android:viewportHeight="24.0"
- android:viewportWidth="24.0"
- android:width="24dp"
- android:tint="?android:attr/colorControlNormal">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M7,11h10v2h-10z"/>
-
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_headset.xml b/packages/SystemUI/res/drawable/ic_headset.xml
index 27efe80..797a80a 100644
--- a/packages/SystemUI/res/drawable/ic_headset.xml
+++ b/packages/SystemUI/res/drawable/ic_headset.xml
@@ -13,19 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
- <vector
- android:width="17.0dp"
- android:height="17.0dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <group
- android:translateY="-1">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19,15v3c0,0.55 -0.45,1 -1,1h-1v-4H19M7,15v4H6c-0.55,0 -1,-0.45 -1,-1v-3H7M12,2c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h3c1.66,0 3,-1.34 3,-3v-7C21,6.03 16.97,2 12,2L12,2z"/>
- </group>
- </vector>
-</inset>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17.0dp"
+ android:height="17.0dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19,15v3c0,0.55 -0.45,1 -1,1h-1v-4h2M7,15v4H6c-0.55,0 -1,-0.45 -1,-1v-3h2m5,-13c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h3c1.66,0 3,-1.34 3,-3v-7c0,-4.97 -4.03,-9 -9,-9z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_headset_mic.xml b/packages/SystemUI/res/drawable/ic_headset_mic.xml
index 1260e0f..b3f006d 100644
--- a/packages/SystemUI/res/drawable/ic_headset_mic.xml
+++ b/packages/SystemUI/res/drawable/ic_headset_mic.xml
@@ -13,16 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
- <vector
- android:width="17.0dp"
- android:height="17.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-1.71C5,6.45 7.96,3.11 11.79,3C15.76,2.89 19,6.06 19,10v2h-4v8h4v1h-6v2h6c1.1,0 2,-0.9 2,-2V10C21,5.03 16.97,1 12,1zM7,14v4H6c-0.55,0 -1,-0.45 -1,-1v-3H7zM19,18h-2v-4h2V18z"/>
- </vector>
-</inset>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17.0dp"
+ android:height="17.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-1.71C5,6.45 7.96,3.11 11.79,3C15.76,2.89 19,6.06 19,10v2h-4v8h4v1h-6v2h6c1.1,0 2,-0.9 2,-2V10C21,5.03 16.97,1 12,1zM7,14v4H6c-0.55,0 -1,-0.45 -1,-1v-3H7zM19,18h-2v-4h2V18z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_hotspot.xml b/packages/SystemUI/res/drawable/ic_hotspot.xml
index 8450bf6..b6fa798 100644
--- a/packages/SystemUI/res/drawable/ic_hotspot.xml
+++ b/packages/SystemUI/res/drawable/ic_hotspot.xml
@@ -15,14 +15,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="18dp"
+ android:height="18dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
- <group
- android:translateY="-0.32">
- <path
- android:pathData="M12,11c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,13a6,6 0,0 0,-6.75 -5.95c-2.62,0.32 -4.78,2.41 -5.18,5.02 -0.32,2.14 0.49,4.11 1.92,5.39 0.48,0.43 1.24,0.33 1.56,-0.23 0.24,-0.42 0.14,-0.94 -0.22,-1.26a3.99,3.99 0,0 1,-1.22 -3.94,3.954 3.954,0 0,1 2.9,-2.91A4.007,4.007 0,0 1,16 13c0,1.18 -0.51,2.23 -1.33,2.96 -0.36,0.33 -0.47,0.85 -0.23,1.27 0.31,0.54 1.04,0.69 1.5,0.28A5.97,5.97 0,0 0,18 13zM10.83,3.07c-4.62,0.52 -8.35,4.33 -8.78,8.96a9.966,9.966 0,0 0,4.02 9.01c0.48,0.35 1.16,0.2 1.46,-0.31 0.25,-0.43 0.14,-0.99 -0.26,-1.29 -2.28,-1.69 -3.65,-4.55 -3.16,-7.7 0.54,-3.5 3.46,-6.29 6.98,-6.68C15.91,4.51 20,8.28 20,13c0,2.65 -1.29,4.98 -3.27,6.44 -0.4,0.3 -0.51,0.85 -0.26,1.29 0.3,0.52 0.98,0.66 1.46,0.31A9.96,9.96 0,0 0,22 13c0,-5.91 -5.13,-10.62 -11.17,-9.93z"
- android:fillColor="#FFFFFFFF"/>
- </group>
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M12,7c-3.31,0 -6,2.69 -6,6 0,1.66 0.68,3.15 1.76,4.24l1.42,-1.42C8.45,15.1 8,14.11 8,13c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,1.11 -0.45,2.1 -1.18,2.82l1.42,1.42C17.32,16.15 18,14.66 18,13c0,-3.31 -2.69,-6 -6,-6zM12,3C6.48,3 2,7.48 2,13c0,2.76 1.12,5.26 2.93,7.07l1.41,-1.41C4.9,17.21 4,15.21 4,13c0,-4.42 3.58,-8 8,-8s8,3.58 8,8c0,2.21 -0.9,4.2 -2.35,5.65l1.41,1.41C20.88,18.26 22,15.76 22,13c0,-5.52 -4.48,-10 -10,-10zM12,11c-1.1,0 -2,0.9 -2,2 0,0.55 0.23,1.05 0.59,1.41 0.36,0.36 0.86,0.59 1.41,0.59s1.05,-0.23 1.41,-0.59c0.36,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2z" />
+
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml b/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml
deleted file mode 100644
index 7641998..0000000
--- a/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:name="root"
- android:height="48dp"
- android:width="48dp"
- android:viewportHeight="48"
- android:viewportWidth="48" >
- <group
- android:name="ic_hotspot"
- android:translateX="23.97354"
- android:translateY="24.26306" >
- <group
- android:name="ic_hotspot_pivot"
- android:translateX="-23.21545"
- android:translateY="-18.86649" >
- <clip-path
- android:name="mask"
- android:pathData="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 43.1884765625,43.515335083 43.1884765625,43.515335083 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -42.9885101318,-43.0112609863 -42.9885101318,-43.0112609863 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 13.0984039307,13.025604248 13.0984039307,13.025604248 c 0.0,0.0 -3.13299560547,2.82977294922 -3.13299560547,2.82977294922 c 0.0,0.0 16.571762085,22.0471801758 16.571762085,22.0471801758 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z" />
- <group
- android:name="cross" >
- <path
- android:name="cross_1"
- android:pathData="M 4.44044494629,2.24310302734 c 0.0,0.0 35.4000396729,35.3999633789 35.4000396729,35.3999633789 "
- android:strokeColor="#FFFFFFFF"
- android:strokeAlpha="1"
- android:strokeWidth="3.5"
- android:fillColor="#00000000" />
- </group>
- <group
- android:name="hotspot"
- android:translateX="23.481"
- android:translateY="18.71151" >
- <group
- android:name="circles"
- android:translateX="-0.23909"
- android:translateY="-0.10807" >
- <path
- android:name="circle_3"
- android:pathData="M 0.0843505859375,-2.93901062012 c -2.30102539062,0.0 -4.16702270508,1.86602783203 -4.16702270508,4.16702270508 c 0.0,2.29898071289 1.86599731445,4.16598510742 4.16702270508,4.16598510742 c 2.29998779297,0.0 4.16598510742,-1.86700439453 4.16598510742,-4.16598510742 c 0.0,-2.30099487305 -1.86599731445,-4.16702270508 -4.16598510742,-4.16702270508 Z M 11.1185302734,5.83390808105 c 0.0,0.0 0.0009765625,0.00100708007812 0.0009765625,0.00100708007812 c 0.14501953125,-0.356994628906 0.27099609375,-0.725006103516 0.382995605469,-1.09799194336 c 0.0570068359375,-0.195007324219 0.101013183594,-0.394989013672 0.149017333984,-0.595001220703 c 0.0690002441406,-0.281005859375 0.126983642578,-0.563995361328 0.175994873047,-0.851989746094 c 0.0270080566406,-0.169006347656 0.0559997558594,-0.337005615234 0.0759887695313,-0.509002685547 c 0.0580139160156,-0.468017578125 0.0970153808594,-0.942993164062 0.0970153808593,-1.4280090332 c 0.0,0.0 0.0,-0.00100708007812 0.0,-0.00100708007812 c 0.0,-5.03900146484 -3.11099243164,-9.3450012207 -7.5119934082,-11.1229858398 c -0.00601196289062,-0.00299072265625 -0.0130004882812,-0.0050048828125 -0.0190124511719,-0.00701904296875 c -0.686004638672,-0.275970458984 -1.39999389648,-0.492980957031 -2.14099121094,-0.638977050781 c -0.072998046875,-0.0150146484375 -0.149017333984,-0.02099609375 -0.222991943359,-0.0339965820313 c -0.302001953125,-0.0540161132812 -0.605010986328,-0.106018066406 -0.916015625,-0.136016845703 c -0.389984130859,-0.0390014648438 -0.786987304688,-0.0599975585938 -1.18899536133,-0.0599975585937 c -0.402008056641,0.0 -0.799011230469,0.02099609375 -1.19000244141,0.0599975585937 c -0.304992675781,0.0299987792969 -0.602996826172,0.0809936523438 -0.901000976563,0.132995605469 c -0.0790100097656,0.0150146484375 -0.160003662109,0.02099609375 -0.238006591797,0.0370178222656 c -0.368988037109,0.0719909667969 -0.730987548828,0.164001464844 -1.08700561523,0.269989013672 c -0.00299072265625,0.00100708007812 -0.0059814453125,0.00201416015625 -0.00900268554687,0.0020141601562 c -0.351989746094,0.10498046875 -0.694000244141,0.226989746094 -1.0309753418,0.361999511719 c -0.0110168457031,0.00399780273438 -0.0220031738281,0.00698852539062 -0.0320129394531,0.0119934082031 c -4.40200805664,1.77798461914 -7.51098632812,6.083984375 -7.5119934082,11.1229858398 c 0.0,0.00799560546875 0.00198364257812,0.0160217285156 0.0019836425781,0.0240173339844 c 0.00100708007812,0.475006103516 0.0380249023438,0.940002441406 0.0950012207032,1.39898681641 c 0.02001953125,0.175994873047 0.0490112304688,0.348999023438 0.0780029296875,0.523010253906 c 0.0469970703125,0.281982421875 0.105010986328,0.557983398438 0.171997070312,0.833984375 c 0.0480041503906,0.204010009766 0.093017578125,0.410003662109 0.152008056641,0.610015869141 c 0.110992431641,0.372009277344 0.238006591797,0.736999511719 0.382019042969,1.09298706055 c 0.0,0.0 0.0009765625,0.0 0.0009765625,0.0 c 1.00701904297,2.48400878906 2.81301879883,4.56100463867 5.11001586914,5.89501953125 c 0.0,0.0 2.01599121094,-3.48300170898 2.01599121094,-3.48300170898 c -2.03900146484,-1.18402099609 -3.5119934082,-3.22500610352 -3.89898681641,-5.63900756836 c 0.0,0.0 0.0009765625,-0.00100708007812 0.0009765625,-0.00100708007812 c -0.0220031738281,-0.130981445312 -0.0369873046875,-0.265991210938 -0.052978515625,-0.399993896484 c -0.0290222167969,-0.274993896484 -0.0570068359375,-0.552001953125 -0.0570068359375,-0.834991455078 c 0.0,0.0 0.0,-0.0190124511719 0.0,-0.0190124511719 c 0.0,-3.98999023438 2.92498779297,-7.28900146484 6.74398803711,-7.89199829102 c 0.0,0.0 0.0180053710938,0.0169982910156 0.0180053710938,0.0169982910156 c 0.404998779297,-0.0639953613281 0.81298828125,-0.125 1.23599243164,-0.125 c 0.0,0.0 0.00201416015625,0.0 0.00201416015624,0.0 c 0.0,0.0 0.00299072265625,0.0 0.00299072265626,0.0 c 0.423004150391,0.0 0.830017089844,0.0610046386719 1.23501586914,0.125 c 0.0,0.0 0.0169982910156,-0.0180053710938 0.0169982910156,-0.0180053710938 c 3.81997680664,0.60400390625 6.74499511719,3.90301513672 6.74499511719,7.89199829102 c 0.0,0.292999267578 -0.0280151367188,0.578002929688 -0.0589904785156,0.861999511719 c -0.0150146484375,0.132019042969 -0.0290222167969,0.264007568359 -0.051025390625,0.393005371094 c -0.385986328125,2.41500854492 -1.85897827148,4.45599365234 -3.89797973633,5.64001464844 c 0.0,0.0 2.01599121094,3.48300170898 2.01599121094,3.48300170898 c 2.29699707031,-1.33401489258 4.10299682617,-3.41101074219 5.11001586914,-5.89602661133 Z M 19.9300231934,2.95698547363 c 0.0059814453125,-0.0659790039062 0.0159912109375,-0.130981445312 0.02099609375,-0.196990966797 c 0.031982421875,-0.462005615234 0.0479736328125,-0.928009033203 0.0489807128906,-1.39700317383 c 0,0.0 0,-0.00997924804688 0,-0.00997924804687 c 0,0.0 0,-0.00100708007812 0,-0.00100708007813 c 0,-7.22500610352 -3.84399414062,-13.5360107422 -9.58599853516,-17.0500183105 c -1.06500244141,-0.652984619141 -2.19299316406,-1.20599365234 -3.37799072266,-1.65197753906 c -0.157989501953,-0.0599975585938 -0.317016601562,-0.118011474609 -0.476989746094,-0.174011230469 c -0.317016601562,-0.110992431641 -0.634002685547,-0.218994140625 -0.9580078125,-0.31298828125 c -0.470001220703,-0.139007568359 -0.944000244141,-0.264007568359 -1.4280090332,-0.368011474609 c -0.186004638672,-0.0390014648438 -0.376983642578,-0.0669860839844 -0.565002441406,-0.101013183594 c -0.414001464844,-0.0759887695312 -0.832000732422,-0.140991210938 -1.25500488281,-0.190979003906 c -0.184997558594,-0.0220031738281 -0.369995117188,-0.0429992675781 -0.556976318359,-0.0599975585937 c -0.592010498047,-0.0530090332031 -1.18801879883,-0.0899963378906 -1.79602050781,-0.0899963378907 c -0.605987548828,0.0 -1.20300292969,0.0369873046875 -1.79598999023,0.0899963378907 c -0.186004638672,0.0169982910156 -0.371002197266,0.0379943847656 -0.555999755859,0.0599975585937 c -0.423004150391,0.0499877929688 -0.842010498047,0.114990234375 -1.25601196289,0.190979003906 c -0.18798828125,0.0350036621094 -0.377990722656,0.06201171875 -0.563995361328,0.101013183594 c -0.483001708984,0.10400390625 -0.959991455078,0.22900390625 -1.42999267578,0.368011474609 c -0.321990966797,0.093994140625 -0.638000488281,0.201995849609 -0.953002929688,0.311981201172 c -0.162994384766,0.0570068359375 -0.324005126953,0.115997314453 -0.484985351562,0.177001953125 c -1.18099975586,0.445007324219 -2.30599975586,0.997009277344 -3.36801147461,1.64700317383 c -0.00201416015625,0.00100708007812 -0.00399780273438,0.00201416015625 -0.0060119628907,0.0029907226562 c -5.74099731445,3.51400756836 -9.58499145508,9.82501220703 -9.58599853516,17.0500183105 c 0,0.0 0,0.00100708007812 0,0.00100708007813 c 0,0.0059814453125 0.00100708007812,0.0130004882812 0.0010070800781,0.0199890136719 c 0.0,0.466003417969 0.0169982910156,0.928009033203 0.0490112304688,1.38598632812 c 0.0050048828125,0.0690002441406 0.0159912109375,0.136016845703 0.02099609375,0.206024169922 c 0.031982421875,0.401000976562 0.0719909667969,0.799987792969 0.127990722656,1.19400024414 c 0.00201416015625,0.0189819335938 0.00701904296875,0.0369873046875 0.010009765625,0.0569763183594 c 0.888000488281,6.17202758789 4.59799194336,11.4250183105 9.7799987793,14.4309997559 c 0.0,0.0 2.00198364258,-3.458984375 2.00198364258,-3.458984375 c -2.58599853516,-1.5 -4.708984375,-3.70401000977 -6.11697387695,-6.34399414063 c 0.0,0.0 0.0169982910156,-0.0180053710938 0.0169982910156,-0.0180053710938 c -0.890014648438,-1.67098999023 -1.50601196289,-3.5110168457 -1.76000976562,-5.46499633789 c -0.00698852539062,-0.0500183105469 -0.010009765625,-0.102020263672 -0.0159912109375,-0.152008056641 c -0.0330200195312,-0.273010253906 -0.0610046386719,-0.545989990234 -0.0800170898437,-0.821990966797 c -0.0220031738281,-0.343017578125 -0.0350036621094,-0.68701171875 -0.0350036621094,-1.03500366211 c 0,-6.53701782227 3.92599487305,-12.1480102539 9.54299926758,-14.6310119629 c 0.157012939453,-0.0700073242188 0.313995361328,-0.135986328125 0.472015380859,-0.199981689453 c 0.373992919922,-0.151000976562 0.751983642578,-0.294006347656 1.13900756836,-0.417022705078 c 0.108978271484,-0.0350036621094 0.221984863281,-0.0619812011719 0.332000732422,-0.0950012207031 c 0.349975585938,-0.102996826172 0.705993652344,-0.194976806641 1.06597900391,-0.273986816406 c 0.114013671875,-0.0249938964844 0.227996826172,-0.052001953125 0.342010498047,-0.0750122070313 c 0.440002441406,-0.0869750976562 0.885986328125,-0.154998779297 1.33700561523,-0.203979492188 c 0.10400390625,-0.0120239257812 0.209991455078,-0.02001953125 0.315002441406,-0.0299987792969 c 0.47998046875,-0.0429992675781 0.963989257812,-0.072998046875 1.45397949219,-0.072998046875 c 0.492004394531,0.0 0.975006103516,0.0299987792969 1.45401000977,0.072998046875 c 0.105987548828,0.00997924804688 0.212005615234,0.0179748535156 0.316986083984,0.0299987792969 c 0.450012207031,0.0489807128906 0.89501953125,0.117004394531 1.33502197266,0.203002929688 c 0.115997314453,0.0239868164062 0.22998046875,0.0509948730469 0.345001220703,0.0769958496094 c 0.358001708984,0.0780029296875 0.710998535156,0.169982910156 1.06097412109,0.272003173828 c 0.111022949219,0.0329895019531 0.226013183594,0.0609741210938 0.336029052734,0.0969848632813 c 0.385986328125,0.123016357422 0.761993408203,0.265014648438 1.13497924805,0.415008544922 c 0.160003662109,0.0650024414062 0.319000244141,0.131988525391 0.477020263672,0.201995849609 c 5.61599731445,2.48400878906 9.53997802734,8.09399414062 9.53997802734,14.6310119629 c 0,0.346984863281 -0.0130004882812,0.690979003906 -0.0350036621094,1.03399658203 c -0.0179748535156,0.274993896484 -0.0469970703125,0.548004150391 -0.0789794921875,0.819000244141 c -0.00601196289062,0.052001953125 -0.010009765625,0.10498046875 -0.0160217285156,0.154998779297 c -0.252990722656,1.95498657227 -0.871002197266,3.79400634766 -1.75997924805,5.46499633789 c 0.0,0.0 0.0169982910156,0.0180053710938 0.0169982910156,0.0180053710938 c -1.40802001953,2.63998413086 -3.53100585938,4.84399414062 -6.11700439453,6.34399414063 c 0.0,0.0 2.00198364258,3.458984375 2.00198364258,3.458984375 c 5.18402099609,-3.00698852539 8.89501953125,-8.26300048828 9.78100585938,-14.4379882813 c 0.00201416015625,-0.0169982910156 0.00601196289062,-0.0320129394531 0.0079956054688,-0.0490112304688 c 0.0570068359375,-0.39697265625 0.0970153808594,-0.798980712891 0.129028320312,-1.20300292969 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- </group>
- </group>
- </group>
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location.xml b/packages/SystemUI/res/drawable/ic_location.xml
new file mode 100644
index 0000000..50ba523
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright (C) 2014 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
deleted file mode 100644
index dd124b7..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?android:attr/colorControlNormal">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" />
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M 5 10.5 C 5.82842712475 10.5 6.5 11.1715728753 6.5 12 C 6.5 12.8284271247 5.82842712475 13.5 5 13.5 C 4.17157287525 13.5 3.5 12.8284271247 3.5 12 C 3.5 11.1715728753 4.17157287525 10.5 5 10.5 Z" />
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M 19 10.5 C 19.8284271247 10.5 20.5 11.1715728753 20.5 12 C 20.5 12.8284271247 19.8284271247 13.5 19 13.5 C 18.1715728753 13.5 17.5 12.8284271247 17.5 12 C 17.5 11.1715728753 18.1715728753 10.5 19 10.5 Z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
index 220c63c..1c86706 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
@@ -14,13 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?android:attr/colorControlNormal">
-
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" />
-</vector>
+ android:fillColor="@android:color/white"
+ android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_branded_vpn.xml b/packages/SystemUI/res/drawable/ic_qs_branded_vpn.xml
deleted file mode 100644
index b20e158..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_branded_vpn.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="12.0dp"
- android:height="12.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#4DFFFFFF"
- android:pathData="M12.09,9C11.11,7.5 9.43,6.5 7.5,6.5C4.46,6.5 2,8.96 2,12c0,3.04 2.46,5.5 5.5,5.5c1.93,0 3.61,-1 4.59,-2.5H14v3h6v-3h2V9H12.09zM20,13h-2v3h-2v-3h-5.16c-0.43,1.44 -1.76,2.5 -3.34,2.5C5.57,15.5 4,13.93 4,12c0,-1.93 1.57,-3.5 3.5,-3.5c1.58,0 2.9,1.06 3.34,2.5H20V13z"/>
- <path
- android:fillColor="#4DFFFFFF"
- android:pathData="M7.5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
deleted file mode 100644
index 9e57577..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M1,18v2c0,0.55 0.45,1 1,1h2c0,-1.66 -1.34,-3 -3,-3zM0.97,15.06c-0.01,0.51 0.35,0.93 0.85,1.02 2.08,0.36 3.74,2 4.1,4.08 0.09,0.48 0.5,0.84 0.99,0.84 0.61,0 1.09,-0.54 1,-1.14a6.996,6.996 0,0 0,-5.8 -5.78c-0.59,-0.09 -1.12,0.38 -1.14,0.98zM0.97,11.03c-0.01,0.52 0.37,0.96 0.88,1.01 4.26,0.43 7.68,3.82 8.1,8.08 0.05,0.5 0.48,0.88 0.99,0.88 0.59,0 1.06,-0.51 1,-1.1 -0.52,-5.21 -4.66,-9.34 -9.87,-9.85 -0.57,-0.05 -1.08,0.4 -1.1,0.98zM21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2z"
- android:fillColor="#FFFFFFFF" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
deleted file mode 100644
index 3dda87c..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M1,18v2c0,0.55 0.45,1 1,1h2c0,-1.66 -1.34,-3 -3,-3zM0.97,15.06c-0.01,0.51 0.35,0.93 0.85,1.02 2.08,0.36 3.74,2 4.1,4.08 0.09,0.48 0.5,0.84 0.99,0.84 0.61,0 1.09,-0.54 1,-1.14a6.996,6.996 0,0 0,-5.8 -5.78c-0.59,-0.09 -1.12,0.38 -1.14,0.98zM19,7L5,7v1.63c3.96,1.28 7.09,4.41 8.37,8.37L19,17L19,7zM0.97,11.03c-0.01,0.52 0.37,0.96 0.88,1.01 4.26,0.43 7.68,3.82 8.1,8.08 0.05,0.5 0.48,0.88 0.99,0.88 0.59,0 1.06,-0.51 1,-1.1 -0.52,-5.21 -4.66,-9.34 -9.87,-9.85 -0.57,-0.05 -1.08,0.4 -1.1,0.98zM21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_vpn.xml b/packages/SystemUI/res/drawable/ic_qs_vpn.xml
deleted file mode 100644
index 6567d12..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_vpn.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="12.0dp"
- android:height="12.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.09,9C11.11,7.5 9.43,6.5 7.5,6.5C4.46,6.5 2,8.96 2,12c0,3.04 2.46,5.5 5.5,5.5c1.93,0 3.61,-1 4.59,-2.5H14v3h6v-3h2V9H12.09zM20,13h-2v3h-2v-3h-5.16c-0.43,1.44 -1.76,2.5 -3.34,2.5C5.57,15.5 4,13.93 4,12c0,-1.93 1.57,-3.5 3.5,-3.5c1.58,0 2.9,1.06 3.34,2.5H20V13z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M7.5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_alarm.xml b/packages/SystemUI/res/drawable/ic_volume_alarm.xml
index 996e488..771b466 100644
--- a/packages/SystemUI/res/drawable/ic_volume_alarm.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_alarm.xml
@@ -14,14 +14,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="24.0dp"
- android:viewportHeight="24.0"
- android:viewportWidth="24.0"
- android:width="24.0dp"
- android:tint="?android:attr/colorControlNormal">
-
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
<path
android:fillColor="#FFFFFF"
- android:pathData="M2.7,6.5c-0.4,-0.4 -0.3,-1 0.1,-1.4l3,-2.6c0.4,-0.4 1,-0.3 1.4,0.1C7.6,3 7.5,3.7 7.1,4l-3,2.6C3.6,7 3,6.9 2.7,6.5zM21.3,5.1l-3.1,-2.6c-0.4,-0.4 -0.99,-0.31 -1.4,0.1c-0.4,0.4 -0.3,1 0.1,1.4L20,6.6c0.41,0.37 1,0.3 1.4,-0.1C21.73,6.12 21.7,5.4 21.3,5.1zM21,13c0,5 -4,9 -9,9s-9,-4 -9,-9s4,-9 9,-9S21,8 21,13zM19.1,13c0,-3.9 -3.2,-7.1 -7.1,-7.1S4.9,9.1 4.9,13s3.2,7.1 7.1,7.1S19.1,16.9 19.1,13zM11.75,8C11.34,8 11,8.34 11,8.75V14l4.14,2.48c0.34,0.21 0.77,0.1 0.98,-0.24s0.09,-0.79 -0.25,-0.99l-3.37,-2v-4.5C12.5,8.34 12.16,8 11.75,8z"/>
+ android:pathData="M13,8h-2v5.41l3.79,3.8 1.42,-1.42 -3.21,-3.2zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7zM16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM2.056,5.654L6.663,1.81l1.28,1.536L3.338,7.19z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml b/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
index 02fb1e7..18e2736 100644
--- a/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
@@ -22,6 +22,6 @@
<path
android:fillColor="#FFFFFF"
- 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.41zM20.72,20.09a0.9,0.9 0,0 1,0 1.27,0.9 0.9,0 0,1 -1.27,0l-1.57,-1.57A8.875,8.875 0,0 1,12 22c-4.98,0 -9,-4.03 -9,-9 0,-2.25 0.83,-4.31 2.2,-5.89l-0.8,-0.8 -0.41,0.35a1,1 0,0 1,-1.35 -0.06,1 1,0 0,1 0.07,-1.47l0.27,-0.23 -0.7,-0.7a0.9,0.9 0,0 1,0 -1.27c0.35,-0.35 0.93,-0.35 1.28,0l17.16,17.16zM16.54,18.45L6.55,8.46A7.041,7.041 0,0 0,4.9 13c0,3.91 3.19,7.1 7.1,7.1 1.73,0 3.31,-0.62 4.54,-1.65zM7.17,3.98A0.997,0.997 0,1 0,5.9 2.44l-0.16,0.13 1.42,1.42 0.01,-0.01zM12,4c-1.41,0 -2.73,0.33 -3.92,0.91l1.45,1.45c0.77,-0.29 1.6,-0.46 2.47,-0.46 3.91,0 7.1,3.18 7.1,7.1 0,0.87 -0.17,1.7 -0.45,2.47l1.44,1.44c0.58,-1.18 0.91,-2.5 0.91,-3.91a9,9 0,0 0,-9 -9z"/>
+ android:pathData="M16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM9.35,6.52C10.17,6.19 11.06,6 12,6c3.86,0 7,3.14 7,7 0,0.94 -0.19,1.83 -0.52,2.65l1.5,1.5C20.63,15.91 21,14.5 21,13c0,-4.97 -4.03,-9 -9,-9 -1.5,0 -2.91,0.37 -4.15,1.02l1.5,1.5zM17.42,17.42L7.58,7.58 6.16,6.16l-0.72,-0.72 -1.42,-1.42 -1.21,-1.21 -1.42,1.41L2.48,5.3l-0.42,0.35 1.28,1.54 0.56,-0.47 0.9,0.9C3.67,9.12 3,10.98 3,13c0,4.97 4.03,9 9,9 2.02,0 3.88,-0.67 5.38,-1.79l2.4,2.4 1.41,-1.41 -2.35,-2.35 -1.42,-1.43zM12,20c-3.86,0 -7,-3.14 -7,-7 0,-1.46 0.46,-2.82 1.23,-3.94l9.71,9.71C14.82,19.54 13.46,20 12,20zM7.94,3.35L6.66,1.81l-1.1,0.92 1.42,1.42z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
index aa13f1e..314e06c 100644
--- a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
@@ -14,11 +14,10 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="24dp"
+ android:height="19dp"
+ android:width="19dp"
android:viewportHeight="24.0"
- android:viewportWidth="24.0"
- android:width="24dp"
- android:tint="?android:attr/colorControlNormal" >
+ android:viewportWidth="24.0">
<path
android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml b/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml
index 2655bcd..0f8c571 100644
--- a/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml
@@ -16,16 +16,5 @@
** limitations under the License.
*/
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="17.25dp"
- android:height="18dp"
- android:viewportWidth="19.65"
- android:viewportHeight="20.5">
- <group
- android:translateX="1.3"
- android:translateY="1.7">
- <path
- android:pathData="M16.01,9.87l-6.24,-3.9v-4.7C9.77,0.57 9.21,0 8.5,0S7.23,0.57 7.23,1.28v4.7L0.99,9.88c-0.37,0.23 -0.6,0.64 -0.6,1.08v0.41c0,0.29 0.29,0.5 0.55,0.41l6.27,-1.97v4.7l-1.37,1.02c-0.21,0.16 -0.34,0.41 -0.34,0.68v0.57c0,0.15 0.12,0.23 0.27,0.2 1.67,-0.47 1.12,-0.31 2.73,-0.78 1.03,0.3 1.7,0.49 2.72,0.78 0.15,0.03 0.27,-0.06 0.27,-0.2v-0.57c0,-0.27 -0.13,-0.52 -0.34,-0.68l-1.37,-1.02v-4.7l6.27,1.97c0.28,0.09 0.55,-0.12 0.55,-0.41v-0.41c0.01,-0.45 -0.23,-0.87 -0.59,-1.09z"
- android:fillColor="#FFF"/>
- </group>
-</vector>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@*android:drawable/ic_qs_airplane" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_alarm.xml b/packages/SystemUI/res/drawable/stat_sys_alarm.xml
index 0e9319c..b9bebec 100644
--- a/packages/SystemUI/res/drawable/stat_sys_alarm.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_alarm.xml
@@ -1,35 +1,21 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
-**
-** Copyright 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.
+ *
+ * Copyright 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.
*/
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
- <vector
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="19.3"
- android:viewportHeight="19.3">
- <group
- android:translateX="1.2"
- android:translateY="1.2">
- <path
- android:pathData="M0.97,3.97c-0.32,-0.33 -0.24,-0.81 0.08,-1.13L3.47,0.74C3.79,0.42 4.28,0.5 4.6,0.82s0.24,0.89 -0.08,1.13L2.1,4.05c-0.4,0.32 -0.89,0.24 -1.13,-0.08zM15.97,2.84l-2.5,-2.1c-0.32,-0.32 -0.8,-0.25 -1.13,0.08 -0.32,0.32 -0.24,0.81 0.08,1.13l2.5,2.1c0.33,0.3 0.81,0.24 1.13,-0.08 0.27,-0.31 0.25,-0.89 -0.08,-1.13zM15.73,9.21c0,4.03 -3.23,7.26 -7.26,7.26s-7.26,-3.23 -7.26,-7.26 3.23,-7.26 7.26,-7.26 7.26,3.23 7.26,7.26zM14.2,9.21c0,-3.15 -2.58,-5.73 -5.73,-5.73S2.74,6.06 2.74,9.21s2.58,5.73 5.73,5.73 5.73,-2.59 5.73,-5.73zM8.27,5.18c-0.33,0 -0.6,0.27 -0.6,0.6v4.23l3.34,2c0.27,0.17 0.62,0.08 0.79,-0.19s0.07,-0.64 -0.2,-0.8L8.87,9.41L8.87,5.78c0,-0.33 -0.27,-0.6 -0.6,-0.6z"
- android:fillColor="#FFF"/>
- </group>
- </vector>
-</inset>
+ android:insetRight="2.5dp"
+ android:drawable="@drawable/ic_alarm" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml b/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml
index c8e2ac1..cf1119d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml
@@ -15,18 +15,5 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
-
- <vector
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="#4dffffff"
- android:pathData="M22.0,5.7l-4.6,-3.9l-1.3,1.5l4.6,3.9L22.0,5.7zM7.9,3.4L6.6,1.9L2.0,5.7l1.3,1.5L7.9,3.4zM12.5,8.0L11.0,8.0l0.0,6.0l4.7,2.9l0.8,-1.2l-4.0,-2.4L12.5,8.0zM12.0,4.0c-5.0,0.0 -9.0,4.0 -9.0,9.0c0.0,5.0 4.0,9.0 9.0,9.0s9.0,-4.0 9.0,-9.0C21.0,8.0 17.0,4.0 12.0,4.0zM12.0,20.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.9 3.1,-7.0 7.0,-7.0c3.9,0.0 7.0,3.1 7.0,7.0C19.0,16.9 15.9,20.0 12.0,20.0z"/>
-
- </vector>
-
-</inset>
\ No newline at end of file
+ android:insetRight="2.5dp"
+ android:drawable="@drawable/ic_alarm_dim" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_branded_vpn.xml b/packages/SystemUI/res/drawable/stat_sys_branded_vpn.xml
index bfae857..5913cdf 100644
--- a/packages/SystemUI/res/drawable/stat_sys_branded_vpn.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_branded_vpn.xml
@@ -13,6 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<!-- This icon is statically overlayed - do not remove.-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17.0dp"
android:height="17.0dp"
diff --git a/packages/SystemUI/res/drawable/stat_sys_cast.xml b/packages/SystemUI/res/drawable/stat_sys_cast.xml
index 5228085..de7ec9d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_cast.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_cast.xml
@@ -15,14 +15,5 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
- <vector android:width="17dp"
- android:height="17dp"
- android:viewportWidth="17.0"
- android:viewportHeight="17.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M0.71,12.75v1.42c0,0.39 0.32,0.71 0.71,0.71h1.42C2.83,13.7 1.88,12.75 0.71,12.75zM0.69,10.67c-0.01,0.36 0.25,0.66 0.6,0.72c1.47,0.26 2.65,1.42 2.9,2.89c0.06,0.34 0.35,0.6 0.7,0.6c0.43,0 0.77,-0.38 0.71,-0.81c-0.34,-2.11 -2,-3.76 -4.11,-4.09C1.08,9.91 0.7,10.24 0.69,10.67zM13.46,4.96H3.54v1.15c2.81,0.91 5.02,3.12 5.93,5.93h3.99V4.96zM0.69,7.81C0.68,8.18 0.95,8.49 1.31,8.53c3.02,0.3 5.44,2.71 5.74,5.72c0.04,0.35 0.34,0.62 0.7,0.62c0.42,0 0.75,-0.36 0.71,-0.78c-0.37,-3.69 -3.3,-6.62 -6.99,-6.98C1.06,7.08 0.7,7.4 0.69,7.81zM14.88,2.12H2.12c-0.78,0 -1.42,0.64 -1.42,1.42v2.12h1.42V3.54h12.75v9.92H9.92v1.42h4.96c0.78,0 1.42,-0.64 1.42,-1.42V3.54C16.29,2.76 15.65,2.12 14.88,2.12z" />
- </vector>
-</inset>
+ android:insetRight="2.5dp"
+ android:drawable="@drawable/ic_cast_connected" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml
deleted file mode 100644
index 4dc0e4b..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="17.0"
- android:viewportHeight="17.0">
- <group
- android:translateY="0.5"
- android:translateX="0.5" >
- <path
- android:pathData="M8.84,8l2.62,-2.62c0.29,-0.29 0.29,-0.75 0,-1.04L8.33,1.22L8.31,1.2c-0.3,-0.28 -0.76,-0.26 -1.03,0.04c-0.13,0.13 -0.2,0.31 -0.2,0.5v4.51L4.24,3.4c-0.29,-0.29 -0.74,-0.29 -1.03,0s-0.29,0.74 0,1.03L6.78,8l-3.56,3.56c-0.29,0.29 -0.29,0.74 0,1.03s0.74,0.29 1.03,0l2.83,-2.83v4.51c0,0.4 0.33,0.73 0.73,0.73c0.18,0 0.36,-0.07 0.5,-0.2l0.03,-0.03l3.12,-3.12c0.29,-0.29 0.29,-0.75 0,-1.04L8.84,8zM8.47,6.37V3.36l1.5,1.5L8.47,6.37zM8.47,12.63V9.62l1.5,1.5L8.47,12.63z"
- android:fillColor="#FFFFFF"/>
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
index c8a4440..8d9e561 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
@@ -1,31 +1,17 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
-**
-** Copyright 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.
-*/
+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.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="18.0"
- android:viewportHeight="18.0">
- <group
- android:translateY="0.5"
- android:translateX="0.5" >
- <path
- android:pathData="M9.57,8.5l2.79,-2.78c0.3,-0.3 0.3,-0.8 0,-1.1L9.04,1.29L9.02,1.27C8.7,0.98 8.21,1 7.91,1.31C7.78,1.45 7.71,1.64 7.71,1.84v4.79L4.69,3.61c-0.3,-0.3 -0.79,-0.3 -1.09,0s-0.3,0.79 0,1.09L7.39,8.5L3.6,12.29c-0.3,0.3 -0.3,0.79 0,1.09s0.79,0.3 1.09,0l3.01,-3.01v4.8c0,0.42 0.35,0.77 0.77,0.77c0.19,0 0.39,-0.07 0.53,-0.21l0.04,-0.04l3.32,-3.32c0.3,-0.3 0.3,-0.8 0,-1.1L9.57,8.5zM9.19,6.77v-3.2l1.6,1.6L9.19,6.77zM9.19,13.42v-3.2l1.6,1.6L9.19,13.42zM4.03,9.29c-0.44,0.44 -1.15,0.44 -1.58,0C2.02,8.86 2.02,8.16 2.45,7.72l0.01,-0.01C2.89,7.27 3.59,7.27 4.02,7.7l0.01,0.01C4.47,8.15 4.47,8.85 4.03,9.29zM14.44,7.71c0.44,0.44 0.44,1.15 0,1.58c-0.44,0.44 -1.15,0.44 -1.58,0c-0.44,-0.43 -0.44,-1.13 -0.01,-1.57l0.01,-0.01C13.3,7.28 14,7.27 14.43,7.7C14.44,7.7 14.44,7.71 14.44,7.71z"
- android:fillColor="#FFFFFF"/>
- </group>
-</vector>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_bluetooth_connected" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_saver.xml b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
index fed7cae..0223501 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
@@ -18,26 +18,5 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="2.5dp"
- android:insetRight="2.5dp" >
- <vector
- android:width="18dp"
- android:height="18dp"
- android:viewportWidth="19.0"
- android:viewportHeight="19.0">
- <group
- android:translateX="1.0"
- android:translateY="1.0">
- <path
- android:pathData="M11.5,8.5c0,0.41 -0.34,0.74 -0.74,0.74L9.24,9.24v1.5c0,0.41 -0.34,0.74 -0.74,0.74s-0.74,-0.34 -0.74,-0.74v-1.5h-1.5c-0.41,0 -0.74,-0.34 -0.74,-0.74s0.34,-0.74 0.74,-0.74h1.5v-1.5c0,-0.41 0.34,-0.74 0.74,-0.74s0.74,0.34 0.74,0.74v1.5h1.5c0.42,-0.01 0.76,0.33 0.76,0.74z"
- android:fillColor="#FFF"/>
- <path
- android:pathData="M13.23,12.05l0.99,0.57c0.19,0.12 0.25,0.38 0.12,0.55A7.452,7.452 0,0 1,7.5 15.9c-3.29,-0.44 -5.96,-3.08 -6.41,-6.38 -0.57,-4.17 2.33,-7.8 6.23,-8.42 0.23,-0.04 0.44,0.15 0.44,0.37v1.15c0,0.18 -0.14,0.33 -0.31,0.37 -2.7,0.52 -4.71,2.96 -4.55,5.83 0.16,2.86 2.57,5.21 5.43,5.29 1.77,0.06 3.38,-0.72 4.44,-1.97 0.11,-0.14 0.31,-0.18 0.46,-0.09z"
- android:fillColor="#FFF" />
- <path
- android:pathData="M14.11,8.5c0,0.62 -0.11,1.22 -0.29,1.78 -0.06,0.17 0.01,0.35 0.16,0.45l1,0.57c0.19,0.12 0.46,0.03 0.54,-0.18 0.3,-0.82 0.47,-1.7 0.47,-2.62 0,-3.73 -2.73,-6.82 -6.31,-7.39a0.377,0.377 0,0 0,-0.44 0.37v1.15c0,0.18 0.14,0.33 0.31,0.36 2.59,0.51 4.56,2.78 4.56,5.51z"
- android:fillAlpha="0.3"
- android:fillColor="#FFF" />
-
- </group>
- </vector>
-</inset>
+ android:insetRight="2.5dp"
+ android:drawable="@drawable/ic_data_saver" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_dnd.xml b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
index 68a06d0..aa352b4 100644
--- a/packages/SystemUI/res/drawable/stat_sys_dnd.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
@@ -18,17 +18,5 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="2.5dp"
- android:insetRight="2.5dp" >
- <vector
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M7,11h10v2h-10z"/>
- </vector>
-</inset>
+ android:insetRight="2.5dp"
+ android:drawable="@*android:drawable/ic_qs_dnd" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_headset.xml b/packages/SystemUI/res/drawable/stat_sys_headset.xml
new file mode 100644
index 0000000..361c665
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_headset.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="2.5dp"
+ android:insetRight="2.5dp"
+ android:drawable="@drawable/ic_headset" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_headset_mic.xml b/packages/SystemUI/res/drawable/stat_sys_headset_mic.xml
new file mode 100644
index 0000000..b424caa
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_headset_mic.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="2.5dp"
+ android:insetRight="2.5dp"
+ android:drawable="@drawable/ic_headset_mic" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_hotspot.xml b/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
index 4f52777..361b00a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
@@ -15,18 +15,5 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
- <vector
- android:width="18.0dp"
- android:height="18.0dp"
- android:viewportWidth="18.0"
- android:viewportHeight="18.0">
- <group
- android:translateX="0.5"
- android:translateY="0.5" >
- <path
- android:pathData="M8.5,7.79c-0.78,0 -1.42,0.64 -1.42,1.42c0,0.78 0.64,1.42 1.42,1.42s1.42,-0.64 1.42,-1.42C9.92,8.43 9.28,7.79 8.5,7.79zM12.75,9.21c0,-2.35 -1.9,-4.25 -4.25,-4.25c-0.18,0 -0.35,0.01 -0.53,0.03C6.11,5.22 4.58,6.7 4.3,8.55c-0.23,1.52 0.35,2.91 1.36,3.82C6,12.67 6.54,12.6 6.76,12.2c0.17,-0.3 0.1,-0.67 -0.16,-0.89c-0.78,-0.7 -1.12,-1.77 -0.86,-2.79C5.99,7.5 6.78,6.71 7.8,6.46C9.32,6.08 10.86,7 11.25,8.52c0.06,0.23 0.09,0.46 0.09,0.69c0,0.84 -0.36,1.58 -0.94,2.1c-0.25,0.23 -0.33,0.6 -0.16,0.9c0.22,0.38 0.74,0.49 1.06,0.2C12.22,11.6 12.75,10.43 12.75,9.21zM7.63,1.85C4.19,2.24 1.42,5.07 1.1,8.52c-0.26,2.61 0.88,5.15 2.99,6.7c0.36,0.26 0.86,0.15 1.09,-0.23c0.19,-0.32 0.1,-0.74 -0.19,-0.96c-1.7,-1.26 -2.71,-3.38 -2.35,-5.73c0.4,-2.6 2.57,-4.68 5.19,-4.97c3.59,-0.41 6.63,2.4 6.63,5.91c0,1.97 -0.96,3.7 -2.43,4.79c-0.3,0.22 -0.38,0.63 -0.19,0.96c0.22,0.39 0.73,0.49 1.09,0.23c1.9,-1.4 3.03,-3.62 3.03,-5.98C15.94,4.84 12.12,1.34 7.63,1.85z"
- android:fillColor="#FFFFFFFF"/>
- </group>
- </vector>
-</inset>
+ android:insetRight="2.5dp"
+ android:drawable="@drawable/ic_hotspot" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_location.xml b/packages/SystemUI/res/drawable/stat_sys_location.xml
index bdb0b0c..7a5aeb9 100644
--- a/packages/SystemUI/res/drawable/stat_sys_location.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_location.xml
@@ -14,18 +14,6 @@
~ limitations under the License
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="1.5dp"
- android:insetRight="1.5dp">
- <vector
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
- </vector>
-</inset>
\ No newline at end of file
+ android:insetLeft="2.5dp"
+ android:insetRight="2.5dp"
+ android:drawable="@drawable/ic_location" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
index 0b72f75..21a4c17 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
@@ -1,36 +1,19 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
-**
-** Copyright 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.
-*/
+ 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.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
- <vector
- android:width="19dp"
- android:height="19dp"
- android:viewportWidth="23.0"
- android:viewportHeight="23.0">
- <group
- android:translateX="-0.5"
- android:translateY="-0.5">
- <path
- android:fillColor="#F00"
- android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/>
-
- </group>
- </vector>
-</inset>
+ android:insetRight="2.5dp"
+ android:drawable="@drawable/ic_volume_ringer_vibrate" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_zen_important.xml b/packages/SystemUI/res/drawable/stat_sys_zen_important.xml
deleted file mode 100644
index 1262617..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_zen_important.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
- <vector android:width="18dp"
- android:height="18dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.0,17.273l6.1800003,3.7269993 -1.6350002,-7.0290003 5.455,-4.7269993 -7.191,-0.6170006 -2.809,-6.627 -2.809,6.627 -7.191,0.6170006 5.455,4.7269993 -1.6349998,7.0290003z"/>
- </vector>
-</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_zen_none.xml b/packages/SystemUI/res/drawable/stat_sys_zen_none.xml
deleted file mode 100644
index 92914a8..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_zen_none.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
- <vector android:width="17dp"
- android:height="17dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0C44.0,13.0 35.0,4.0 24.0,4.0zM24.0,40.0c-8.8,0.0 -16.0,-7.2 -16.0,-16.0c0.0,-3.7 1.3,-7.1 3.4,-9.8l22.4,22.4C31.1,38.7 27.7,40.0 24.0,40.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8z"/>
- </vector>
-</inset>
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index 9acfbaf..c420117 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -54,6 +54,8 @@
android:background="@drawable/rounded_ripple"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:scaleType="fitCenter"
+ android:padding="@dimen/volume_dialog_ringer_icon_padding"
android:tint="@color/accent_tint_color_selector"
android:layout_gravity="center"
android:soundEffectsEnabled="false" />
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml
deleted file mode 100644
index 665fc3f..0000000
--- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:fillViewport ="true"
- android:orientation="vertical">
-
- <LinearLayout
- android:id="@+id/dialog_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:textDirection="locale"
- android:textAppearance="@style/TextAppearance.AppOpsDialog.Title"
- android:textColor="@*android:color/text_color_primary"
- android:layout_marginStart="@dimen/ongoing_appops_dialog_title_margin_sides"
- android:layout_marginEnd="@dimen/ongoing_appops_dialog_title_margin_sides"
- android:layout_marginBottom="@dimen/ongoing_appops_dialog_title_margin_top_bottom"
- android:layout_marginTop="@dimen/ongoing_appops_dialog_title_margin_top_bottom"
- />
-
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/ongoing_appops_dialog_items_bottom_margin" >
-
- <LinearLayout
- android:id="@+id/items_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:gravity="start"
- />
- </LinearLayout>
-
- </LinearLayout>
-
-</ScrollView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
deleted file mode 100644
index c8e0845..0000000
--- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="@dimen/ongoing_appops_dialog_line_height"
- android:layout_marginStart="@dimen/ongoing_appops_dialog_text_padding"
- android:layout_marginEnd="@dimen/ongoing_appops_dialog_text_padding"
- android:fillViewport="true"
- android:orientation="horizontal"
- android:focusable="true"
- android:layout_gravity="center_vertical">
-
- <FrameLayout
- android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size"
- android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size"
- android:layout_gravity="start|center_vertical">
-
- <ImageView
- android:id="@+id/app_icon"
- android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size"
- android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size"
- android:layout_gravity="center"
- />
- </FrameLayout>
-
- <TextView
- android:id="@+id/app_name"
- android:layout_height="match_parent"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:gravity="start|center_vertical"
- android:textDirection="locale"
- android:textAppearance="@style/TextAppearance.AppOpsDialog.Item"
- android:textColor="@*android:color/text_color_primary"
- android:layout_marginStart="@dimen/ongoing_appops_dialog_text_padding"
- />
-
- <LinearLayout
- android:id="@+id/icons"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:gravity="end"
- android:layout_gravity="end|center_vertical"
- android:visibility="gone"
- />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index d1c80c4..a90b1eb 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -56,6 +56,8 @@
android:background="@drawable/rounded_ripple"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:scaleType="fitCenter"
+ android:padding="@dimen/volume_dialog_ringer_icon_padding"
android:tint="@color/accent_tint_color_selector"
android:layout_gravity="center"
android:soundEffectsEnabled="false" />
diff --git a/packages/SystemUI/res/layout/volume_dnd_icon.xml b/packages/SystemUI/res/layout/volume_dnd_icon.xml
index 037d143..10c1472 100644
--- a/packages/SystemUI/res/layout/volume_dnd_icon.xml
+++ b/packages/SystemUI/res/layout/volume_dnd_icon.xml
@@ -24,6 +24,6 @@
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_gravity="right|top"
- android:src="@drawable/ic_dnd"
+ android:src="@*android:drawable/ic_qs_dnd"
android:tint="?android:attr/textColorTertiary"/>
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 039eca6..1a865ee 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -341,6 +341,8 @@
<dimen name="volume_dialog_ringer_size">64dp</dimen>
+ <dimen name="volume_dialog_ringer_icon_padding">20dp</dimen>
+
<dimen name="volume_dialog_caption_size">64dp</dimen>
<dimen name="volume_dialog_tap_target_size">48dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 03b6a52..0411d01 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2345,18 +2345,6 @@
<!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]-->
<string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string>
- <!-- Action for accepting the Ongoing privacy dialog [CHAR LIMIT=10]-->
- <string name="ongoing_privacy_dialog_ok">Got it</string>
-
- <!-- Action on Ongoing Privacy Dialog to open privacy hub [CHAR LIMIT=23]-->
- <string name="ongoing_privacy_dialog_open_settings">Privacy settings</string>
-
- <!-- Text for item in Ongoing Privacy Dialog title when only one app is using app ops [CHAR LIMIT=NONE] -->
- <string name="ongoing_privacy_dialog_single_app_title">App using your <xliff:g id="types_list" example="camera( and location)">%s</xliff:g></string>
-
- <!-- Text for item in Ongoing Privacy Dialog title when multiple apps is using app ops [CHAR LIMIT=NONE] -->
- <string name="ongoing_privacy_dialog_multiple_apps_title">Apps using your <xliff:g id="types_list" example="camera( and location)">%s</xliff:g></string>
-
<!-- Separator for types. Include spaces before and after if needed [CHAR LIMIT=10] -->
<string name="ongoing_privacy_dialog_separator">,\u0020</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index c0ec405..fb4fe81 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -99,13 +99,7 @@
esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
}
- private void showDefaultMessage() {
- if (mRemainingAttempts >= 0) {
- mSecurityMessageDisplay.setMessage(getPinPasswordErrorMessage(
- mRemainingAttempts, true));
- return;
- }
-
+ private void setLockedSimMessage() {
boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
int count = TelephonyManager.getDefault().getSimCount();
Resources rez = getResources();
@@ -122,13 +116,20 @@
color = info.getIconTint();
}
}
-
if (isEsimLocked) {
msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
}
mSecurityMessageDisplay.setMessage(msg);
mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+ }
+
+ private void showDefaultMessage() {
+ setLockedSimMessage();
+ if (mRemainingAttempts >= 0) {
+ return;
+ }
+
// Sending empty PIN here to query the number of remaining PIN attempts
new CheckSimPin("", mSubId) {
@@ -137,8 +138,7 @@
" attemptsRemaining=" + attemptsRemaining);
if (attemptsRemaining >= 0) {
mRemainingAttempts = attemptsRemaining;
- mSecurityMessageDisplay.setMessage(
- getPinPasswordErrorMessage(attemptsRemaining, true));
+ setLockedSimMessage();
}
}
}.start();
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
index 32c1242..147def39 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -15,15 +15,19 @@
*/
package com.android.keyguard.clock;
+import android.app.WallpaperManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Color;
import android.graphics.Paint.Style;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextClock;
+import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.R;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.ClockPlugin;
import java.util.TimeZone;
@@ -44,6 +48,16 @@
private final LayoutInflater mLayoutInflater;
/**
+ * Extracts accent color from wallpaper.
+ */
+ private final SysuiColorExtractor mColorExtractor;
+
+ /**
+ * Renders preview from clock view.
+ */
+ private final ViewPreviewer mRenderer = new ViewPreviewer();
+
+ /**
* Custom clock shown on AOD screen and behind stack scroller on lock.
*/
private View mView;
@@ -64,11 +78,15 @@
/**
* Create a BubbleClockController instance.
*
- * @param layoutInflater Inflater used to inflate custom clock views.
+ * @param res Resources contains title and thumbnail.
+ * @param inflater Inflater used to inflate custom clock views.
+ * @param colorExtractor Extracts accent color from wallpaper.
*/
- public BubbleClockController(Resources res, LayoutInflater inflater) {
+ public BubbleClockController(Resources res, LayoutInflater inflater,
+ SysuiColorExtractor colorExtractor) {
mResources = res;
mLayoutInflater = inflater;
+ mColorExtractor = colorExtractor;
}
private void createViews() {
@@ -99,6 +117,23 @@
}
@Override
+ public Bitmap getPreview(int width, int height) {
+
+ // Use the big clock view for the preview
+ View view = getBigClockView();
+
+ // Initialize state of plugin before generating preview.
+ setDarkAmount(1f);
+ setTextColor(Color.WHITE);
+ ColorExtractor.GradientColors colors = mColorExtractor.getColors(
+ WallpaperManager.FLAG_LOCK, true);
+ setColorPalette(colors.supportsDarkText(), colors.getColorPalette());
+ onTimeTick();
+
+ return mRenderer.createPreview(view, width, height);
+ }
+
+ @Override
public View getView() {
if (mLockClockContainer == null) {
createViews();
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 8ad5c7b..d0fff74 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -16,29 +16,19 @@
package com.android.keyguard.clock;
import android.annotation.Nullable;
-import android.app.WallpaperManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
-import android.util.Log;
import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.view.ViewGroup;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.colorextraction.ColorExtractor;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dock.DockManager;
@@ -51,8 +41,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.FutureTask;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -128,7 +116,6 @@
private final List<ClockChangedListener> mListeners = new ArrayList<>();
- private final SysuiColorExtractor mColorExtractor;
private final int mWidth;
private final int mHeight;
@@ -144,17 +131,16 @@
ContentResolver contentResolver, SettingsWrapper settingsWrapper) {
mContext = context;
mPluginManager = pluginManager;
- mColorExtractor = colorExtractor;
mContentResolver = contentResolver;
mSettingsWrapper = settingsWrapper;
Resources res = context.getResources();
LayoutInflater layoutInflater = injectionInflater.injectable(LayoutInflater.from(context));
- addClockPlugin(new DefaultClockController(res, layoutInflater));
- addClockPlugin(new BubbleClockController(res, layoutInflater));
- addClockPlugin(new StretchAnalogClockController(res, layoutInflater));
- addClockPlugin(new TypeClockController(res, layoutInflater));
+ addClockPlugin(new DefaultClockController(res, layoutInflater, colorExtractor));
+ addClockPlugin(new BubbleClockController(res, layoutInflater, colorExtractor));
+ addClockPlugin(new StretchAnalogClockController(res, layoutInflater, colorExtractor));
+ addClockPlugin(new TypeClockController(res, layoutInflater, colorExtractor));
// Store the size of the display for generation of clock preview.
DisplayMetrics dm = res.getDisplayMetrics();
@@ -217,7 +203,7 @@
.setTitle(plugin.getTitle())
.setId(id)
.setThumbnail(() -> plugin.getThumbnail())
- .setPreview(() -> getClockPreview(id))
+ .setPreview(() -> plugin.getPreview(mWidth, mHeight))
.build());
}
@@ -232,81 +218,6 @@
}
}
- /**
- * Generate a realistic preview of a clock face.
- * @param clockId ID of clock to use for preview, should be obtained from {@link getClockInfos}.
- * Returns null if clockId is not found.
- */
- @Nullable
- private Bitmap getClockPreview(String clockId) {
- FutureTask<Bitmap> task = new FutureTask<>(new Callable<Bitmap>() {
- @Override
- public Bitmap call() {
- Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_8888);
- ClockPlugin plugin = mClocks.get(clockId);
- if (plugin == null) {
- return null;
- }
-
- // Use the big clock view for the preview
- View clockView = plugin.getBigClockView();
- if (clockView == null) {
- return null;
- }
-
- // Initialize state of plugin before generating preview.
- plugin.setDarkAmount(1f);
- plugin.setTextColor(Color.WHITE);
-
- ColorExtractor.GradientColors colors = mColorExtractor.getColors(
- WallpaperManager.FLAG_LOCK, true);
- plugin.setColorPalette(colors.supportsDarkText(), colors.getColorPalette());
- plugin.onTimeTick();
-
- // Draw clock view hierarchy to canvas.
- Canvas canvas = new Canvas(bitmap);
- canvas.drawColor(Color.BLACK);
- dispatchVisibilityAggregated(clockView, true);
- clockView.measure(MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY));
- clockView.layout(0, 0, mWidth, mHeight);
- clockView.draw(canvas);
- return bitmap;
- }
- });
-
- if (Looper.myLooper() == Looper.getMainLooper()) {
- task.run();
- } else {
- mMainHandler.post(task);
- }
-
- try {
- return task.get();
- } catch (Exception e) {
- Log.e(TAG, "Error completing task", e);
- return null;
- }
- }
-
- private void dispatchVisibilityAggregated(View view, boolean isVisible) {
- // Similar to View.dispatchVisibilityAggregated implementation.
- final boolean thisVisible = view.getVisibility() == View.VISIBLE;
- if (thisVisible || !isVisible) {
- view.onVisibilityAggregated(isVisible);
- }
-
- if (view instanceof ViewGroup) {
- isVisible = thisVisible && isVisible;
- ViewGroup vg = (ViewGroup) view;
- int count = vg.getChildCount();
-
- for (int i = 0; i < count; i++) {
- dispatchVisibilityAggregated(vg.getChildAt(i), isVisible);
- }
- }
- }
-
private void notifyClockChanged(ClockPlugin plugin) {
for (int i = 0; i < mListeners.size(); i++) {
// It probably doesn't make sense to supply the same plugin instances to multiple
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java
index 8a6a4cd..73414b3 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockController.java
@@ -15,15 +15,19 @@
*/
package com.android.keyguard.clock;
+import android.app.WallpaperManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Color;
import android.graphics.Paint.Style;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
+import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.R;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.ClockPlugin;
import java.util.TimeZone;
@@ -44,6 +48,16 @@
private final LayoutInflater mLayoutInflater;
/**
+ * Extracts accent color from wallpaper.
+ */
+ private final SysuiColorExtractor mColorExtractor;
+
+ /**
+ * Renders preview from clock view.
+ */
+ private final ViewPreviewer mRenderer = new ViewPreviewer();
+
+ /**
* Root view of preview.
*/
private View mView;
@@ -61,11 +75,15 @@
/**
* Create a DefaultClockController instance.
*
+ * @param res Resources contains title and thumbnail.
* @param inflater Inflater used to inflate custom clock views.
+ * @param colorExtractor Extracts accent color from wallpaper.
*/
- public DefaultClockController(Resources res, LayoutInflater inflater) {
+ public DefaultClockController(Resources res, LayoutInflater inflater,
+ SysuiColorExtractor colorExtractor) {
mResources = res;
mLayoutInflater = inflater;
+ mColorExtractor = colorExtractor;
}
private void createViews() {
@@ -90,6 +108,23 @@
}
@Override
+ public Bitmap getPreview(int width, int height) {
+
+ // Use the big clock view for the preview
+ View view = getBigClockView();
+
+ // Initialize state of plugin before generating preview.
+ setDarkAmount(1f);
+ setTextColor(Color.WHITE);
+ ColorExtractor.GradientColors colors = mColorExtractor.getColors(
+ WallpaperManager.FLAG_LOCK, true);
+ setColorPalette(colors.supportsDarkText(), colors.getColorPalette());
+ onTimeTick();
+
+ return mRenderer.createPreview(view, width, height);
+ }
+
+ @Override
public View getView() {
return null;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
index 34b2fd8..ea9f0cd 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
@@ -15,15 +15,19 @@
*/
package com.android.keyguard.clock;
+import android.app.WallpaperManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Color;
import android.graphics.Paint.Style;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextClock;
+import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.R;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.ClockPlugin;
import java.util.TimeZone;
@@ -44,6 +48,16 @@
private final LayoutInflater mLayoutInflater;
/**
+ * Extracts accent color from wallpaper.
+ */
+ private final SysuiColorExtractor mColorExtractor;
+
+ /**
+ * Renders preview from clock view.
+ */
+ private final ViewPreviewer mRenderer = new ViewPreviewer();
+
+ /**
* Custom clock shown on AOD screen and behind stack scroller on lock.
*/
private View mBigClockView;
@@ -64,11 +78,15 @@
/**
* Create a BubbleClockController instance.
*
- * @param layoutInflater Inflater used to inflate custom clock views.
+ * @param res Resources contains title and thumbnail.
+ * @param inflater Inflater used to inflate custom clock views.
+ * @param colorExtractor Extracts accent color from wallpaper.
*/
- public StretchAnalogClockController(Resources res, LayoutInflater inflater) {
+ public StretchAnalogClockController(Resources res, LayoutInflater inflater,
+ SysuiColorExtractor colorExtractor) {
mResources = res;
mLayoutInflater = inflater;
+ mColorExtractor = colorExtractor;
}
private void createViews() {
@@ -99,6 +117,23 @@
}
@Override
+ public Bitmap getPreview(int width, int height) {
+
+ // Use the big clock view for the preview
+ View view = getBigClockView();
+
+ // Initialize state of plugin before generating preview.
+ setDarkAmount(1f);
+ setTextColor(Color.WHITE);
+ ColorExtractor.GradientColors colors = mColorExtractor.getColors(
+ WallpaperManager.FLAG_LOCK, true);
+ setColorPalette(colors.supportsDarkText(), colors.getColorPalette());
+ onTimeTick();
+
+ return mRenderer.createPreview(view, width, height);
+ }
+
+ @Override
public View getView() {
if (mView == null) {
createViews();
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
index 387f265..67c0989 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
@@ -15,14 +15,18 @@
*/
package com.android.keyguard.clock;
+import android.app.WallpaperManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Color;
import android.graphics.Paint.Style;
import android.view.LayoutInflater;
import android.view.View;
+import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.R;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.ClockPlugin;
import java.util.TimeZone;
@@ -43,6 +47,16 @@
private final LayoutInflater mLayoutInflater;
/**
+ * Extracts accent color from wallpaper.
+ */
+ private final SysuiColorExtractor mColorExtractor;
+
+ /**
+ * Renders preview from clock view.
+ */
+ private final ViewPreviewer mRenderer = new ViewPreviewer();
+
+ /**
* Custom clock shown on AOD screen and behind stack scroller on lock.
*/
private View mView;
@@ -61,11 +75,15 @@
/**
* Create a TypeClockController instance.
*
+ * @param res Resources contains title and thumbnail.
* @param inflater Inflater used to inflate custom clock views.
+ * @param colorExtractor Extracts accent color from wallpaper.
*/
- TypeClockController(Resources res, LayoutInflater inflater) {
+ TypeClockController(Resources res, LayoutInflater inflater,
+ SysuiColorExtractor colorExtractor) {
mResources = res;
mLayoutInflater = inflater;
+ mColorExtractor = colorExtractor;
}
private void createViews() {
@@ -96,6 +114,23 @@
}
@Override
+ public Bitmap getPreview(int width, int height) {
+
+ // Use the big clock view for the preview
+ View view = getBigClockView();
+
+ // Initialize state of plugin before generating preview.
+ setDarkAmount(1f);
+ setTextColor(Color.WHITE);
+ ColorExtractor.GradientColors colors = mColorExtractor.getColors(
+ WallpaperManager.FLAG_LOCK, true);
+ setColorPalette(colors.supportsDarkText(), colors.getColorPalette());
+ onTimeTick();
+
+ return mRenderer.createPreview(view, width, height);
+ }
+
+ @Override
public View getView() {
if (mLockClock == null) {
createViews();
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ViewPreviewer.java b/packages/SystemUI/src/com/android/keyguard/clock/ViewPreviewer.java
new file mode 100644
index 0000000..abd0dd2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ViewPreviewer.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+
+/**
+ * Creates a preview image ({@link Bitmap}) of a {@link View} for a custom clock face.
+ */
+final class ViewPreviewer {
+
+ private static final String TAG = "ViewPreviewer";
+
+ /**
+ * Handler used to run {@link View#draw(Canvas)} on the main thread.
+ */
+ private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+
+ /**
+ * Generate a realistic preview of a clock face.
+ *
+ * @param view view is used to generate preview image.
+ * @param width width of the preview image, should be the same as device width in pixels.
+ * @param height height of the preview image, should be the same as device height in pixels.
+ * @return bitmap of view.
+ */
+ @Nullable
+ Bitmap createPreview(View view, int width, int height) {
+ if (view == null) {
+ return null;
+ }
+ FutureTask<Bitmap> task = new FutureTask<>(new Callable<Bitmap>() {
+ @Override
+ public Bitmap call() {
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+
+ // Draw clock view hierarchy to canvas.
+ Canvas canvas = new Canvas(bitmap);
+ canvas.drawColor(Color.BLACK);
+ dispatchVisibilityAggregated(view, true);
+ view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+ view.layout(0, 0, width, height);
+ view.draw(canvas);
+
+ return bitmap;
+ }
+ });
+
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ task.run();
+ } else {
+ mMainHandler.post(task);
+ }
+
+ try {
+ return task.get();
+ } catch (Exception e) {
+ Log.e(TAG, "Error completing task", e);
+ return null;
+ }
+ }
+
+ private void dispatchVisibilityAggregated(View view, boolean isVisible) {
+ // Similar to View.dispatchVisibilityAggregated implementation.
+ final boolean thisVisible = view.getVisibility() == View.VISIBLE;
+ if (thisVisible || !isVisible) {
+ view.onVisibilityAggregated(isVisible);
+ }
+
+ if (view instanceof ViewGroup) {
+ isVisible = thisVisible && isVisible;
+ ViewGroup vg = (ViewGroup) view;
+ int count = vg.getChildCount();
+
+ for (int i = 0; i < count; i++) {
+ dispatchVisibilityAggregated(vg.getChildAt(i), isVisible);
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 559c9f6..de887ff 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -381,10 +381,18 @@
}
/**
- * Update bubble expanded view header when user toggles dark mode.
+ * Update header color when user toggles dark mode.
*/
void updateHeaderColor() {
- mHeaderView.setBackgroundColor(mContext.getColor(R.attr.colorAccent));
+ TypedArray ta = mContext.obtainStyledAttributes(
+ new int[] {android.R.attr.colorBackgroundFloating, android.R.attr.colorForeground});
+ int bgColor = ta.getColor(0, Color.WHITE /* default */);
+ int btnColor = ta.getColor(1, Color.BLACK /* default */);
+ ta.recycle();
+
+ mHeaderView.setBackgroundColor(bgColor);
+ mSettingsIcon.setColorFilter(btnColor);
+ mDeepLinkIcon.setColorFilter(btnColor);
}
private void updateHeaderView() {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 617090a..be55829 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -52,6 +52,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.ViewClippingUtil;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController.DismissReason;
import com.android.systemui.bubbles.animation.ExpandedAnimationController;
@@ -270,8 +271,8 @@
* Handle config changes.
*/
public void onConfigChanged() {
- if (mExpandedBubble != null) {
- mExpandedBubble.expandedView.updateHeaderColor();
+ for (Bubble b: mBubbleData.getBubbles()) {
+ b.expandedView.updateHeaderColor();
}
}
@@ -316,7 +317,8 @@
}
switch (action) {
case AccessibilityNodeInfo.ACTION_DISMISS:
- stackDismissed(BubbleController.DISMISS_ACCESSIBILITY_ACTION);
+ Dependency.get(BubbleController.class).dismissStack(
+ BubbleController.DISMISS_ACCESSIBILITY_ACTION);
return true;
case AccessibilityNodeInfo.ACTION_COLLAPSE:
collapseStack();
@@ -422,7 +424,7 @@
* Sets the entry that should be expanded and expands if needed.
*/
@VisibleForTesting
- public void setExpandedBubble(NotificationEntry entry) {
+ void setExpandedBubble(NotificationEntry entry) {
for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
BubbleView bv = (BubbleView) mBubbleContainer.getChildAt(i);
if (entry.equals(bv.getEntry())) {
@@ -436,7 +438,7 @@
*
* @param entry the notification to add to the stack of bubbles.
*/
- public void addBubble(NotificationEntry entry) {
+ void addBubble(NotificationEntry entry) {
Bubble b = new Bubble(entry, mInflater, this /* stackView */, mBlockedListener);
mBubbleData.addBubble(b);
@@ -451,12 +453,17 @@
/**
* Remove a bubble from the stack.
*/
- public void removeBubble(String key, int reason) {
+ void removeBubble(String key, int reason) {
Bubble b = mBubbleData.removeBubble(key);
if (b == null) {
return;
}
- int removedIndex = dismissBubble(b, reason);
+ setBubbleDismissed(b, reason);
+
+ // Remove it from the views
+ int removedIndex = mBubbleContainer.indexOfChild(b.iconView);
+ mBubbleContainer.removeViewAt(removedIndex);
+
int bubbleCount = mBubbleContainer.getChildCount();
if (bubbleCount == 0) {
// If no bubbles remain, collapse the entire stack.
@@ -481,9 +488,9 @@
/**
* Dismiss the stack of bubbles.
*/
- public void stackDismissed(int reason) {
+ void stackDismissed(int reason) {
for (Bubble bubble : mBubbleData.getBubbles()) {
- dismissBubble(bubble, reason);
+ setBubbleDismissed(bubble, reason);
}
mBubbleData.clear();
collapseStack();
@@ -495,8 +502,7 @@
}
/**
- * Marks the notification entry as dismissed, cleans up Bubble icon and expanded view UI
- * elements and calls deleteIntent if necessary.
+ * Marks the notification entry as dismissed & calls any delete intents for the bubble.
*
* <p>Note: This does not remove the Bubble from BubbleData.
*
@@ -504,17 +510,13 @@
* @param reason code for the reason the dismiss was triggered
* @see BubbleController.DismissReason
*/
- private int dismissBubble(Bubble bubble, @DismissReason int reason) {
+ private void setBubbleDismissed(Bubble bubble, @DismissReason int reason) {
if (DEBUG) {
Log.d(TAG, "dismissBubble: " + bubble + " reason=" + reason);
}
bubble.entry.setBubbleDismissed(true);
bubble.expandedView.cleanUpExpandedState();
- // Remove it from the views
- int removedIndex = mBubbleContainer.indexOfChild(bubble.iconView);
- mBubbleContainer.removeViewAt(removedIndex);
-
if (reason == BubbleController.DISMISS_USER_GESTURE) {
Notification.BubbleMetadata bubbleMetadata = bubble.entry.getBubbleMetadata();
PendingIntent deleteIntent = bubbleMetadata != null
@@ -529,7 +531,6 @@
}
}
}
- return removedIndex;
}
/**
@@ -856,7 +857,6 @@
private void applyCurrentState() {
Log.d(TAG, "applyCurrentState: mIsExpanded=" + mIsExpanded);
-
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
if (mIsExpanded) {
// First update the view so that it calculates a new height (ensuring the y position
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
index 8731b6b..0f659c3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
@@ -799,4 +799,9 @@
}
}
}
+
+ @Override
+ protected boolean canReceivePointerEvents() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index a4592d5..3c6dc73 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -87,7 +87,8 @@
}
private void requestPulseOutNow(State dozeState) {
- if (dozeState == State.DOZE_REQUEST_PULSE || dozeState == State.DOZE_PULSING) {
+ if (dozeState == State.DOZE_REQUEST_PULSE || dozeState == State.DOZE_PULSING
+ || dozeState == State.DOZE_PULSING_BRIGHT) {
final int pulseReason = mMachine.getPulseReason();
if (pulseReason == DozeLog.PULSE_REASON_DOCKING) {
mDozeHost.stopPulsing();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 36e28dc..0607654 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -71,7 +71,7 @@
new DozeScreenState(wrappedService, handler, params, wakeLock),
createDozeScreenBrightness(context, wrappedService, sensorManager, host, params,
handler),
- new DozeWallpaperState(context, machine),
+ new DozeWallpaperState(context),
new DozeDockHandler(context, machine, host, config, handler, dockManager)
});
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index bd7a421..3c9d4a9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -33,7 +33,11 @@
boolean isProvisioned();
boolean isBlockingDoze();
- void extendPulse();
+ /**
+ * Makes a current pulse last for twice as long.
+ * @param reason why we're extending it.
+ */
+ void extendPulse(int reason);
void setAnimateWakeup(boolean animateWakeup);
void setAnimateScreenOff(boolean animateScreenOff);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index c243899..8bf2256 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -59,6 +59,8 @@
DOZE_REQUEST_PULSE,
/** Pulse is showing. Device is awake and showing UI. */
DOZE_PULSING,
+ /** Pulse is showing with bright wallpaper. Device is awake and showing UI. */
+ DOZE_PULSING_BRIGHT,
/** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
DOZE_PULSE_DONE,
/** Doze is done. DozeService is finished. */
@@ -84,6 +86,7 @@
switch (this) {
case DOZE_REQUEST_PULSE:
case DOZE_PULSING:
+ case DOZE_PULSING_BRIGHT:
return true;
default:
return false;
@@ -101,6 +104,7 @@
case DOZE:
return Display.STATE_OFF;
case DOZE_PULSING:
+ case DOZE_PULSING_BRIGHT:
return Display.STATE_ON;
case DOZE_AOD:
case DOZE_AOD_PAUSING:
@@ -188,7 +192,10 @@
@MainThread
public State getState() {
Assert.isMainThread();
- Preconditions.checkState(!isExecutingTransition());
+ if (isExecutingTransition()) {
+ throw new IllegalStateException("Cannot get state because there were pending "
+ + "transitions: " + mQueuedRequests.toString());
+ }
return mState;
}
@@ -202,6 +209,7 @@
Assert.isMainThread();
Preconditions.checkState(mState == State.DOZE_REQUEST_PULSE
|| mState == State.DOZE_PULSING
+ || mState == State.DOZE_PULSING_BRIGHT
|| mState == State.DOZE_PULSE_DONE, "must be in pulsing state, but is " + mState);
return mPulseReason;
}
@@ -283,7 +291,8 @@
break;
case DOZE_PULSE_DONE:
Preconditions.checkState(
- mState == State.DOZE_REQUEST_PULSE || mState == State.DOZE_PULSING);
+ mState == State.DOZE_REQUEST_PULSE || mState == State.DOZE_PULSING
+ || mState == State.DOZE_PULSING_BRIGHT);
break;
default:
break;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 1dd3101..bd6882c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -56,6 +56,7 @@
private boolean mRegistered;
private int mDefaultDozeBrightness;
private boolean mPaused = false;
+ private boolean mScreenOff = false;
private int mLastSensorValue = -1;
/**
@@ -118,6 +119,7 @@
break;
}
if (newState != DozeMachine.State.FINISH) {
+ setScreenOff(newState == DozeMachine.State.DOZE);
setPaused(newState == DozeMachine.State.DOZE_AOD_PAUSED);
}
}
@@ -135,15 +137,15 @@
try {
if (mRegistered) {
mLastSensorValue = (int) event.values[0];
- updateBrightnessAndReady();
+ updateBrightnessAndReady(false /* force */);
}
} finally {
Trace.endSection();
}
}
- private void updateBrightnessAndReady() {
- if (mRegistered || mDebugBrightnessBucket != -1) {
+ private void updateBrightnessAndReady(boolean force) {
+ if (force || mRegistered || mDebugBrightnessBucket != -1) {
int sensorValue = mDebugBrightnessBucket == -1
? mLastSensorValue : mDebugBrightnessBucket;
int brightness = computeBrightness(sensorValue);
@@ -153,7 +155,7 @@
}
int scrimOpacity = -1;
- if (mPaused) {
+ if (mPaused || mScreenOff) {
// If AOD is paused, force the screen black until the
// sensor reports a new brightness. This ensures that when the screen comes on
// again, it will only show after the brightness sensor has stabilized,
@@ -216,13 +218,20 @@
private void setPaused(boolean paused) {
if (mPaused != paused) {
mPaused = paused;
- updateBrightnessAndReady();
+ updateBrightnessAndReady(false /* force */);
+ }
+ }
+
+ private void setScreenOff(boolean screenOff) {
+ if (mScreenOff != screenOff) {
+ mScreenOff = screenOff;
+ updateBrightnessAndReady(true /* force */);
}
}
@Override
public void onReceive(Context context, Intent intent) {
mDebugBrightnessBucket = intent.getIntExtra(BRIGHTNESS_BUCKET, -1);
- updateBrightnessAndReady();
+ updateBrightnessAndReady(false /* force */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 7189a48..0fe6611 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -16,6 +16,7 @@
package com.android.systemui.doze;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.UiModeManager;
import android.content.BroadcastReceiver;
@@ -147,7 +148,7 @@
boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0;
if (isWakeDisplay) {
- onWakeScreen(wakeEvent, mMachine.getState());
+ onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
} else if (isLongPress) {
requestPulse(pulseReason, sensorPerformedProxCheck);
} else if (isWakeLockScreen) {
@@ -168,7 +169,7 @@
} else if (isPickup) {
gentleWakeUp(pulseReason);
} else {
- mDozeHost.extendPulse();
+ mDozeHost.extendPulse(pulseReason);
}
}, sensorPerformedProxCheck
|| (mDockManager != null && mDockManager.isDocked()), pulseReason);
@@ -212,7 +213,8 @@
final boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
final boolean aod = (state == DozeMachine.State.DOZE_AOD);
- if (state == DozeMachine.State.DOZE_PULSING) {
+ if (state == DozeMachine.State.DOZE_PULSING
+ || state == DozeMachine.State.DOZE_PULSING_BRIGHT) {
boolean ignoreTouch = near;
if (DEBUG) Log.i(TAG, "Prox changed, ignore touch = " + ignoreTouch);
mDozeHost.onIgnoreTouchWhilePulsing(ignoreTouch);
@@ -227,10 +229,14 @@
}
}
- private void onWakeScreen(boolean wake, DozeMachine.State state) {
+ /**
+ * When a wake screen event is received from a sensor
+ * @param wake {@code true} when it's time to wake up, {@code false} when we should sleep.
+ * @param state The current state, or null if the state could not be determined due to enqueued
+ * transitions.
+ */
+ private void onWakeScreen(boolean wake, @Nullable DozeMachine.State state) {
DozeLog.traceWakeDisplay(wake);
- boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
- boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
sWakeDisplaySensorState = wake;
if (wake) {
@@ -244,6 +250,8 @@
}
}, false /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
} else {
+ boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
+ boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
if (!pausing && !paused) {
mMachine.requestState(DozeMachine.State.DOZE);
}
@@ -276,6 +284,7 @@
mDozeSensors.setListening(false);
break;
case DOZE_PULSING:
+ case DOZE_PULSING_BRIGHT:
mDozeSensors.setTouchscreenSensorsListening(false);
mDozeSensors.setProxListening(true);
break;
@@ -306,7 +315,16 @@
private void requestPulse(final int reason, boolean performedProxCheck) {
Assert.isMainThread();
- mDozeHost.extendPulse();
+ mDozeHost.extendPulse(reason);
+
+ // When already pulsing we're allowed to show the wallpaper directly without
+ // requesting a new pulse.
+ if (mMachine.getState() == DozeMachine.State.DOZE_PULSING
+ && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+ mMachine.requestState(DozeMachine.State.DOZE_PULSING_BRIGHT);
+ return;
+ }
+
if (mPulsePending || !mAllowPulseTriggers || !canPulse()) {
if (mAllowPulseTriggers) {
DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 847182d..51e96d2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -94,7 +94,10 @@
@Override
public void onPulseStarted() {
try {
- mMachine.requestState(DozeMachine.State.DOZE_PULSING);
+ mMachine.requestState(
+ reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
+ ? DozeMachine.State.DOZE_PULSING_BRIGHT
+ : DozeMachine.State.DOZE_PULSING);
} catch (IllegalStateException e) {
// It's possible that the pulse was asynchronously cancelled while
// we were waiting for it to start (under stress conditions.)
@@ -148,6 +151,7 @@
switch (state) {
case DOZE_REQUEST_PULSE:
case DOZE_PULSING:
+ case DOZE_PULSING_BRIGHT:
case DOZE_PULSE_DONE:
mHost.setAnimateWakeup(true);
break;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index ca9f24f..1b3cd88 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -38,19 +38,17 @@
private final IWallpaperManager mWallpaperManagerService;
private final DozeParameters mDozeParameters;
- private final DozeMachine mMachine;
private boolean mIsAmbientMode;
- public DozeWallpaperState(Context context, DozeMachine machine) {
- this(machine, IWallpaperManager.Stub.asInterface(
+ public DozeWallpaperState(Context context) {
+ this(IWallpaperManager.Stub.asInterface(
ServiceManager.getService(Context.WALLPAPER_SERVICE)),
DozeParameters.getInstance(context));
}
@VisibleForTesting
- DozeWallpaperState(DozeMachine machine, IWallpaperManager wallpaperManagerService,
+ DozeWallpaperState(IWallpaperManager wallpaperManagerService,
DozeParameters parameters) {
- mMachine = machine;
mWallpaperManagerService = wallpaperManagerService;
mDozeParameters = parameters;
}
@@ -65,16 +63,13 @@
case DOZE_AOD_PAUSED:
case DOZE_REQUEST_PULSE:
case DOZE_PULSE_DONE:
+ case DOZE_PULSING:
isAmbientMode = true;
break;
- case DOZE_PULSING:
- isAmbientMode =
- mMachine.getPulseReason() != DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
- break;
+ case DOZE_PULSING_BRIGHT:
default:
isAmbientMode = false;
}
-
final boolean animated;
if (isAmbientMode) {
animated = mDozeParameters.shouldControlScreenOff();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index b03b872..6f50baa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -286,8 +286,9 @@
RowBuilder dndBuilder = new RowBuilder(mDndUri)
.setContentDescription(getContext().getResources()
.getString(R.string.accessibility_quick_settings_dnd))
- .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.stat_sys_dnd),
- ListBuilder.ICON_IMAGE);
+ .addEndItem(
+ IconCompat.createWithResource(getContext(), R.drawable.stat_sys_dnd),
+ ListBuilder.ICON_IMAGE);
builder.addRow(dndBuilder);
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
index d7a2d9a..02ad0f1 100644
--- a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
@@ -17,7 +17,8 @@
val timeRemainingMillis: Long,
val severeThresholdMillis: Long,
val lowThresholdMillis: Long,
- val isBasedOnUsage: Boolean
+ val isBasedOnUsage: Boolean,
+ val isLowWarningEnabled: Boolean
) {
/**
* Returns whether hybrid warning logic/copy should be used for this snapshot
@@ -48,7 +49,8 @@
NO_ESTIMATE_AVAILABLE.toLong(),
NO_ESTIMATE_AVAILABLE.toLong(),
NO_ESTIMATE_AVAILABLE.toLong(),
- false
+ false,
+ true
) {
this.isHybrid = false
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
index bd130f4..a879227 100644
--- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
@@ -23,4 +23,9 @@
* show a severe warning to the user.
*/
long getSevereWarningThreshold();
+
+ /**
+ * Returns a boolean indicating if the low warning should be shown at all or not.
+ */
+ boolean getLowWarningEnabled();
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
index 3f24176..bfb809e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
@@ -21,4 +21,9 @@
public long getSevereWarningThreshold() {
return 0;
}
+
+ @Override
+ public boolean getLowWarningEnabled() {
+ return true;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 1863860..4e41108 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -284,7 +284,8 @@
plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1],
mLowBatteryReminderLevels[0], estimate.getEstimateMillis(),
mEnhancedEstimates.getSevereWarningThreshold(),
- mEnhancedEstimates.getLowWarningThreshold(), estimate.isBasedOnUsage());
+ mEnhancedEstimates.getLowWarningThreshold(), estimate.isBasedOnUsage(),
+ mEnhancedEstimates.getLowWarningEnabled());
} else {
if (DEBUG) {
Slog.d(TAG, "using standard");
@@ -351,7 +352,6 @@
Slog.d(TAG, "Low warning marked as shown this cycle");
mLowWarningShownThisChargeCycle = true;
}
-
} else if (shouldDismissHybridWarning(currentSnapshot)) {
if (DEBUG) {
Slog.d(TAG, "Dismissing warning");
@@ -375,8 +375,9 @@
return false;
}
- // Only show the low warning once per charge cycle & no battery saver
- final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !snapshot.isPowerSaver()
+ // Only show the low warning if enabled once per charge cycle & no battery saver
+ final boolean canShowWarning = snapshot.isLowWarningEnabled()
+ && !mLowWarningShownThisChargeCycle && !snapshot.isPowerSaver()
&& (snapshot.getTimeRemainingMillis() < snapshot.getLowThresholdMillis()
|| snapshot.getBatteryLevel() <= snapshot.getLowLevelThreshold());
@@ -386,6 +387,7 @@
|| snapshot.getBatteryLevel() <= snapshot.getSevereLevelThreshold());
final boolean canShow = canShowWarning || canShowSevereWarning;
+
if (DEBUG) {
Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith battery snapshot:"
+ " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
index 59b3c34..d08a373 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
@@ -53,9 +53,4 @@
else -> types.map { it.getName(context) }.joinWithAnd().toString()
}
}
-
- fun getDialogTitle(): String {
- return context.getString(R.string.ongoing_privacy_dialog_multiple_apps_title,
- joinTypes())
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 7c937a9..b682cb0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -160,9 +160,9 @@
int footerIconId = R.drawable.ic_info_outline;
if (vpnName != null || vpnNameWorkProfile != null) {
if (mSecurityController.isVpnBranded()) {
- footerIconId = R.drawable.ic_qs_branded_vpn;
+ footerIconId = R.drawable.stat_sys_branded_vpn;
} else {
- footerIconId = R.drawable.ic_qs_vpn;
+ footerIconId = R.drawable.stat_sys_vpn_ic;
}
}
if (mFooterIconId != footerIconId) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 387de71..19e20a9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -43,8 +43,7 @@
/** Quick settings tile: Airplane mode **/
public class AirplaneModeTile extends QSTileImpl<BooleanState> {
- private final Icon mIcon =
- ResourceIcon.get(R.drawable.ic_signal_airplane);
+ private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_airplane);
private final GlobalSetting mSetting;
private final ActivityStarter mActivityStarter;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 5b85498..ca04076 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -147,14 +147,15 @@
state.icon = ResourceIcon.get(R.drawable.ic_bluetooth_transient_animation);
state.contentDescription = state.secondaryLabel;
} else {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
+ state.icon =
+ ResourceIcon.get(com.android.internal.R.drawable.ic_qs_bluetooth);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth) + ","
+ mContext.getString(R.string.accessibility_not_connected);
}
state.state = Tile.STATE_ACTIVE;
} else {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
+ state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_bluetooth);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth);
state.state = Tile.STATE_INACTIVE;
@@ -288,7 +289,7 @@
// This method returns Pair<Drawable, String> while first value is the drawable
return BluetoothDeviceLayerDrawable.createLayerDrawable(
context,
- R.drawable.ic_qs_bluetooth_connected,
+ R.drawable.ic_bluetooth_connected,
mBatteryLevel,
mIconScale);
}
@@ -309,7 +310,7 @@
@Override
public Drawable getDrawable(Context context) {
// This method returns Pair<Drawable, String> - the first value is the drawable.
- return context.getDrawable(R.drawable.ic_qs_bluetooth_connected);
+ return context.getDrawable(R.drawable.ic_bluetooth_connected);
}
}
@@ -383,12 +384,12 @@
for (CachedBluetoothDevice device : devices) {
if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
final Item item = new Item();
- item.iconResId = R.drawable.ic_qs_bluetooth_on;
+ item.iconResId = com.android.internal.R.drawable.ic_qs_bluetooth;
item.line1 = device.getName();
item.tag = device;
int state = device.getMaxConnectionState();
if (state == BluetoothProfile.STATE_CONNECTED) {
- item.iconResId = R.drawable.ic_qs_bluetooth_connected;
+ item.iconResId = R.drawable.ic_bluetooth_connected;
int batteryLevel = device.getBatteryLevel();
if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
item.icon = new BluetoothBatteryTileIcon(batteryLevel,1 /* iconScale */);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index bdebf79..415870c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -202,8 +202,8 @@
if (connecting && !state.value) {
state.secondaryLabel = mContext.getString(R.string.quick_settings_connecting);
}
- state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
- : R.drawable.ic_qs_cast_off);
+ state.icon = ResourceIcon.get(state.value ? R.drawable.ic_cast_connected
+ : R.drawable.ic_cast);
if (mWifiConnected || state.value) {
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
if (!state.value) {
@@ -334,7 +334,7 @@
for (CastDevice device : devices) {
if (device.state == CastDevice.STATE_CONNECTED) {
final Item item = new Item();
- item.iconResId = R.drawable.ic_qs_cast_on;
+ item.iconResId = R.drawable.ic_cast_connected;
item.line1 = getDeviceName(device);
item.line2 = mContext.getString(R.string.quick_settings_connected);
item.tag = device;
@@ -354,7 +354,7 @@
final CastDevice device = mVisibleOrder.get(id);
if (!devices.contains(device)) continue;
final Item item = new Item();
- item.iconResId = R.drawable.ic_qs_cast_off;
+ item.iconResId = R.drawable.ic_cast;
item.line1 = getDeviceName(device);
if (device.state == CastDevice.STATE_CONNECTING) {
item.line2 = mContext.getString(R.string.quick_settings_connecting);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 7fcd59f..869fa6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -235,7 +235,7 @@
state.label = getTileLabel();
state.secondaryLabel = TextUtils.emptyIfNull(ZenModeConfig.getDescription(mContext,
zen != Global.ZEN_MODE_OFF, mController.getConfig(), false));
- state.icon = ResourceIcon.get(R.drawable.ic_dnd);
+ state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_dnd);
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
switch (zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index dfa3fb9..2755e98 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -35,7 +35,7 @@
public class FlashlightTile extends QSTileImpl<BooleanState> implements
FlashlightController.FlashlightListener {
- private final Icon mIcon = ResourceIcon.get(R.drawable.ic_signal_flashlight);
+ private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_flashlight);
private final FlashlightController mFlashlightController;
@Inject
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index a0f4e24..837ea9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -37,7 +37,7 @@
/** Quick settings tile: Location **/
public class LocationTile extends QSTileImpl<BooleanState> {
- private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_signal_location);
+ private final Icon mIcon = ResourceIcon.get(R.drawable.ic_location);
private final LocationController mController;
private final KeyguardMonitor mKeyguard;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 21f3d6e..7ca1e44 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -36,7 +36,7 @@
/** Quick settings tile: Rotation **/
public class RotationLockTile extends QSTileImpl<BooleanState> {
- private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_auto_rotate);
+ private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_auto_rotate);
private final RotationLockController mController;
@Inject
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 494e6cd..ead39c69 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -439,6 +439,9 @@
mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
.supportsRoundedCornersOnWindows(mContext.getResources());
+ // Assumes device always starts with back button until launcher tells it that it does not
+ mBackButtonAlpha = 1.0f;
+
// Listen for the package update changes.
if (mDeviceProvisionedController.getCurrentUser() == UserHandle.USER_SYSTEM) {
updateEnabledState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index cb9060b..cf6e64c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -289,4 +289,9 @@
}
}
}
+
+ @Override
+ protected boolean canReceivePointerEvents() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9630727c..d287b92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -552,6 +552,9 @@
mEntry.mIsSystemNotification = isSystemNotification(mContext, mStatusBarNotification);
}
+ isNonblockable |= mEntry.channel.isImportanceLockedByOEM();
+ isNonblockable |= mEntry.channel.isImportanceLockedByCriticalDeviceFunction();
+
if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
if (mEntry.mIsSystemNotification) {
if (mEntry.channel != null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 7905617..211a40a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -70,7 +70,7 @@
private final String mTag;
private final View mView;
- private final BarBackgroundDrawable mBarBackground;
+ protected final BarBackgroundDrawable mBarBackground;
private int mMode;
private boolean mAlwaysOpaque = false;
@@ -152,7 +152,7 @@
return mode == MODE_LIGHTS_OUT || mode == MODE_LIGHTS_OUT_TRANSPARENT;
}
- private static class BarBackgroundDrawable extends Drawable {
+ protected static class BarBackgroundDrawable extends Drawable {
private final int mOpaque;
private final int mSemiTransparent;
private final int mTransparent;
@@ -171,6 +171,7 @@
private int mGradientAlphaStart;
private int mColorStart;
+ private Rect mFrame;
public BarBackgroundDrawable(Context context, int gradientResourceId) {
@@ -190,6 +191,10 @@
mGradient = context.getDrawable(gradientResourceId);
}
+ public void setFrame(Rect frame) {
+ mFrame = frame;
+ }
+
@Override
public void setAlpha(int alpha) {
// noop
@@ -296,7 +301,11 @@
if (mTintFilter != null) {
mPaint.setColorFilter(mTintFilter);
}
- canvas.drawPaint(mPaint);
+ if (mFrame != null) {
+ canvas.drawRect(mFrame, mPaint);
+ } else {
+ canvas.drawPaint(mPaint);
+ }
}
if (mAnimating) {
invalidateSelf(); // keep going
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 236c72c..0731a56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -108,16 +108,13 @@
}
String zen = args.getString("zen");
if (zen != null) {
- int iconId = zen.equals("important") ? R.drawable.stat_sys_zen_important
- : zen.equals("none") ? R.drawable.stat_sys_zen_none
- : 0;
+ int iconId = zen.equals("dnd") ? R.drawable.stat_sys_dnd : 0;
updateSlot("zen", null, iconId);
}
String bt = args.getString("bluetooth");
if (bt != null) {
- int iconId = bt.equals("disconnected") ? R.drawable.stat_sys_data_bluetooth
- : bt.equals("connected") ? R.drawable.stat_sys_data_bluetooth_connected
- : 0;
+ int iconId = bt.equals("connected")
+ ? R.drawable.stat_sys_data_bluetooth_connected : 0;
updateSlot("bluetooth", null, iconId);
}
String location = args.getString("location");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index cbb5d54..9485623 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -988,11 +988,11 @@
if (Intent.ACTION_SCREEN_ON.equals(action)) {
// Enabled and screen is on, start it again if enabled
if (NavBarTintController.isEnabled(getContext())) {
- mNavigationBarView.getColorAdaptionController().start();
+ mNavigationBarView.getTintController().start();
}
} else {
// Screen off disable it
- mNavigationBarView.getColorAdaptionController().stop();
+ mNavigationBarView.getTintController().stop();
}
}
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 3984405..d4cec42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -105,6 +106,10 @@
applyLightsOut(true, false);
}
+ void setBackgroundFrame(Rect frame) {
+ mBarBackground.setFrame(frame);
+ }
+
@Override
protected boolean isLightsOut(int mode) {
return super.isLightsOut(mode) || (mAllowAutoDimWallpaperNotVisible && mAutoDim
@@ -119,6 +124,7 @@
protected void onTransition(int oldMode, int newMode, boolean animate) {
super.onTransition(oldMode, newMode, animate);
applyLightsOut(animate, false /*force*/);
+ mView.onBarTransition(newMode);
}
private void applyLightsOut(boolean animate, boolean force) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index f2d6241..f22ecf6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -30,6 +30,7 @@
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ROTATION;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_VIEWS;
import android.animation.LayoutTransition;
@@ -172,7 +173,7 @@
private RecentsOnboarding mRecentsOnboarding;
private NotificationPanelView mPanelView;
- private NavBarTintController mColorAdaptionController;
+ private NavBarTintController mTintController;
private boolean mAssistantAvailable;
private NavigationPrototypeController mPrototypeController;
private NavigationGestureAction[] mDefaultGestureMap;
@@ -309,9 +310,9 @@
@Override
public void onColorAdaptChanged(boolean enabled) {
if (enabled) {
- mColorAdaptionController.start();
+ mTintController.start();
} else {
- mColorAdaptionController.stop();
+ mTintController.stop();
}
}
@@ -442,15 +443,15 @@
mPrototypeController = new NavigationPrototypeController(context);
mPrototypeController.register();
mPrototypeController.setOnPrototypeChangedListener(mPrototypeListener);
- mColorAdaptionController = new NavBarTintController(this, getLightTransitionsController());
+ mTintController = new NavBarTintController(this, getLightTransitionsController());
IntentFilter filter = new IntentFilter(ACTION_OVERLAY_CHANGED);
filter.addDataScheme("package");
context.registerReceiver(mOverlaysChangedReceiver, filter);
}
- public NavBarTintController getColorAdaptionController() {
- return mColorAdaptionController;
+ public NavBarTintController getTintController() {
+ return mTintController;
}
public BarTransitions getBarTransitions() {
@@ -476,7 +477,7 @@
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
- mColorAdaptionController.onDraw();
+ mTintController.onDraw();
}
private void updateNavigationGestures() {
@@ -557,6 +558,17 @@
return super.onTouchEvent(event);
}
+ void onBarTransition(int newMode) {
+ if (newMode == MODE_OPAQUE) {
+ // If the nav bar background is opaque, stop auto tinting since we know the icons are
+ // showing over a dark background
+ mTintController.stop();
+ getLightTransitionsController().setIconsDark(false /* dark */, true /* animate */);
+ } else {
+ mTintController.start();
+ }
+ }
+
private boolean shouldDeadZoneConsumeTouchEvents(MotionEvent event) {
if (mDeadZone.onTouchEvent(event) || mDeadZoneConsuming) {
switch (event.getActionMasked()) {
@@ -978,9 +990,9 @@
// Color adaption is tied with showing home handle, only avaliable if visible
if (visible) {
- mColorAdaptionController.start();
+ mTintController.start();
} else {
- mColorAdaptionController.stop();
+ mTintController.stop();
}
}
@@ -1206,6 +1218,19 @@
reorient();
notifyVerticalChangedListener(newVertical);
}
+
+ if (QuickStepContract.isGesturalMode(getContext())) {
+ // Update the nav bar background to match the height of the visible nav bar
+ int height = mIsVertical
+ ? getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height_landscape)
+ : getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height);
+ int frameHeight = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_frame_height);
+ mBarTransitions.setBackgroundFrame(new Rect(0, frameHeight - height, w, h));
+ }
+
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@@ -1232,9 +1257,9 @@
}
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
- mColorAdaptionController.start();
+ mTintController.start();
} else {
- mColorAdaptionController.stop();
+ mTintController.stop();
}
}
@@ -1417,7 +1442,7 @@
mGestureHelper.dump(pw);
}
mRecentsOnboarding.dump(pw);
- mColorAdaptionController.dump(pw);
+ mTintController.dump(pw);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
index 81a425c..7dc71f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
@@ -57,6 +57,7 @@
mLightColor = Utils.getColorAttrDefaultColor(lightContext, R.attr.singleToneColor);
mDarkColor = Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor);
mPaint.setAntiAlias(true);
+ setFocusable(false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index b7a7873..183fdb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -201,7 +201,7 @@
mIconController.setIconVisibility(mSlotAlarmClock, false);
// zen
- mIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null);
+ mIconController.setIcon(mSlotZen, R.drawable.stat_sys_dnd, null);
mIconController.setIconVisibility(mSlotZen, false);
// volume
@@ -339,11 +339,11 @@
zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
} else if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
zenVisible = true;
- zenIconId = R.drawable.stat_sys_zen_none;
+ zenIconId = R.drawable.stat_sys_dnd;
zenDescription = mContext.getString(R.string.interruption_level_none);
} else if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
zenVisible = true;
- zenIconId = R.drawable.stat_sys_zen_important;
+ zenIconId = R.drawable.stat_sys_dnd;
zenDescription = mContext.getString(R.string.interruption_level_priority);
}
@@ -388,13 +388,12 @@
}
private final void updateBluetooth() {
- int iconId = R.drawable.stat_sys_data_bluetooth;
+ int iconId = R.drawable.stat_sys_data_bluetooth_connected;
String contentDescription =
mContext.getString(R.string.accessibility_quick_settings_bluetooth_on);
boolean bluetoothVisible = false;
if (mBluetooth != null) {
if (mBluetooth.isBluetoothConnected()) {
- iconId = R.drawable.stat_sys_data_bluetooth_connected;
contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected);
bluetoothVisible = mBluetooth.isBluetoothEnabled();
}
@@ -582,8 +581,8 @@
String contentDescription = mContext.getString(hasMic
? R.string.accessibility_status_bar_headset
: R.string.accessibility_status_bar_headphones);
- mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.ic_headset_mic
- : R.drawable.ic_headset, contentDescription);
+ mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.stat_sys_headset_mic
+ : R.drawable.stat_sys_headset, contentDescription);
mIconController.setIconVisibility(mSlotHeadset, true);
} else {
mIconController.setIconVisibility(mSlotHeadset, false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 1949bad..0d2fe13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -92,7 +92,7 @@
/**
* Scrim opacity when the phone is about to wake-up.
*/
- public static final float AOD2_SCRIM_ALPHA = 0.6f;
+ public static final float WAKE_SENSOR_SCRIM_ALPHA = 0.6f;
/**
* A scrim varies its opacity based on a busyness factor, for example
* how many notifications are currently visible.
@@ -458,6 +458,23 @@
mState.AOD.setAodFrontScrimAlpha(alpha);
}
+ /**
+ * If the lock screen sensor is active.
+ */
+ public void setWakeLockScreenSensorActive(boolean active) {
+ for (ScrimState state : ScrimState.values()) {
+ state.setWakeLockScreenSensorActive(active);
+ }
+
+ if (mState == ScrimState.PULSING) {
+ float newBehindAlpha = mState.getBehindAlpha();
+ if (mCurrentBehindAlpha != newBehindAlpha) {
+ mCurrentBehindAlpha = newBehindAlpha;
+ updateScrims();
+ }
+ }
+ }
+
protected void scheduleUpdate() {
if (mUpdatePending) return;
@@ -904,10 +921,6 @@
}
}
- public void setPulseReason(int pulseReason) {
- ScrimState.PULSING.setPulseReason(pulseReason);
- }
-
public interface Callback {
default void onStart() {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 2f161d5..d152ecd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -19,7 +19,6 @@
import android.graphics.Color;
import android.os.Trace;
-import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -129,16 +128,15 @@
@Override
public void prepare(ScrimState previousState) {
mCurrentInFrontAlpha = 0f;
- if (mPulseReason == DozeLog.PULSE_REASON_NOTIFICATION
- || mPulseReason == DozeLog.PULSE_REASON_DOCKING
- || mPulseReason == DozeLog.PULSE_REASON_INTENT) {
- mCurrentBehindAlpha = previousState.getBehindAlpha();
- } else {
- mCurrentBehindAlpha = ScrimController.AOD2_SCRIM_ALPHA;
- }
mCurrentBehindTint = Color.BLACK;
mBlankScreen = mDisplayRequiresBlanking;
}
+
+ @Override
+ public float getBehindAlpha() {
+ return mWakeLockScreenSensorActive ? ScrimController.WAKE_SENSOR_SCRIM_ALPHA
+ : AOD.getBehindAlpha();
+ }
},
/**
@@ -199,7 +197,7 @@
int mIndex;
boolean mHasBackdrop;
boolean mLaunchingAffordanceWithPreview;
- int mPulseReason;
+ boolean mWakeLockScreenSensorActive;
ScrimState(int index) {
mIndex = index;
@@ -264,10 +262,6 @@
mAodFrontScrimAlpha = aodFrontScrimAlpha;
}
- public void setPulseReason(int pulseReason) {
- mPulseReason = pulseReason;
- }
-
public void setScrimBehindAlphaKeyguard(float scrimBehindAlphaKeyguard) {
mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
}
@@ -287,4 +281,8 @@
public void setHasBackdrop(boolean hasBackdrop) {
mHasBackdrop = hasBackdrop;
}
+
+ public void setWakeLockScreenSensorActive(boolean active) {
+ mWakeLockScreenSensorActive = active;
+ }
}
\ No newline at end of file
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 d7f070f..db91d01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3908,7 +3908,6 @@
@Override
public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
- mScrimController.setPulseReason(reason);
if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"com.android.systemui:LONG_PRESS");
@@ -3916,6 +3915,10 @@
return;
}
+ if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+ mScrimController.setWakeLockScreenSensorActive(true);
+ }
+
boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_NOTIFICATION;
// Set the state to pulsing, so ScrimController will know what to do once we ask it to
// execute the transition. The pulse callback will then be invoked when the scrims
@@ -3934,6 +3937,7 @@
mPulsing = false;
callback.onPulseFinished();
updateNotificationPanelTouchState();
+ mScrimController.setWakeLockScreenSensorActive(false);
setPulsing(false);
}
@@ -4010,7 +4014,10 @@
}
@Override
- public void extendPulse() {
+ public void extendPulse(int reason) {
+ if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+ mScrimController.setWakeLockScreenSensorActive(true);
+ }
if (mDozeScrimController.isPulsing() && mAmbientPulseManager.hasNotifications()) {
mAmbientPulseManager.extendPulse();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index cbaabf7..3b32d95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -760,9 +760,10 @@
}
public boolean bouncerNeedsScrimming() {
- return mOccluded || mBouncer.willDismissWithAction() || mBouncer.needsFullscreenBouncer()
+ return mOccluded || mBouncer.willDismissWithAction()
|| mStatusBar.isFullScreenUserSwitcherState()
- || (mBouncer.isShowing() && mBouncer.isScrimmed());
+ || (mBouncer.isShowing() && mBouncer.isScrimmed())
+ || mBouncer.isFullscreenBouncer();
}
public void dump(PrintWriter pw) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index e5f709a..35a2450 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -288,7 +288,7 @@
addRow(AudioManager.STREAM_RING,
R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true, false);
addRow(STREAM_ALARM,
- R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, true, false);
+ R.drawable.ic_alarm, R.drawable.ic_volume_alarm_mute, true, false);
addRow(AudioManager.STREAM_VOICE_CALL,
com.android.internal.R.drawable.ic_phone,
com.android.internal.R.drawable.ic_phone, false, false);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
index 267468f..f03c234 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
@@ -27,10 +27,13 @@
import android.widget.TextView;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -38,12 +41,15 @@
public final class BubbleClockControllerTest extends SysuiTestCase {
private BubbleClockController mClockController;
+ @Mock SysuiColorExtractor mMockColorExtractor;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
Resources res = getContext().getResources();
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
- mClockController = new BubbleClockController(res, layoutInflater);
+ mClockController = new BubbleClockController(res, layoutInflater, mMockColorExtractor);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
index 0659b4f..26fa62b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
@@ -27,10 +27,13 @@
import android.widget.TextView;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -38,12 +41,16 @@
public final class StretchAnalogClockControllerTest extends SysuiTestCase {
private StretchAnalogClockController mClockController;
+ @Mock SysuiColorExtractor mMockColorExtractor;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
Resources res = getContext().getResources();
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
- mClockController = new StretchAnalogClockController(res, layoutInflater);
+ mClockController = new StretchAnalogClockController(res, layoutInflater,
+ mMockColorExtractor);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ViewPreviewerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/clock/ViewPreviewerTest.kt
new file mode 100644
index 0000000..d9ef7fa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ViewPreviewerTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard.clock
+
+import android.content.Context
+import com.google.common.truth.Truth.assertThat
+
+import android.graphics.Canvas
+import android.graphics.Color
+import android.testing.AndroidTestingRunner
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ViewPreviewerTest : SysuiTestCase() {
+
+ private lateinit var previewer: ViewPreviewer
+ private lateinit var view: View
+
+ @Before
+ fun setUp() {
+ previewer = ViewPreviewer()
+ view = TestView(context)
+ }
+
+ @Test
+ fun testCreatePreview() {
+ val width = 100
+ val height = 100
+ // WHEN a preview image is created
+ val bitmap = previewer.createPreview(view, width, height)
+ // THEN the bitmap has the expected width and height
+ assertThat(bitmap.height).isEqualTo(height)
+ assertThat(bitmap.width).isEqualTo(width)
+ assertThat(bitmap.getPixel(0, 0)).isEqualTo(Color.RED)
+ }
+
+ class TestView(context: Context) : View(context) {
+ override fun onDraw(canvas: Canvas?) {
+ super.onDraw(canvas)
+ canvas?.drawColor(Color.RED)
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index dc42872..abfa755 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -86,7 +86,7 @@
}
@Override
- public void extendPulse() {
+ public void extendPulse(int reason) {
pulseExtended = true;
}
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 cde3398..392c677 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -237,6 +237,18 @@
}
@Test
+ public void screenOff_softBlanks() throws Exception {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+ mScreen.transitionTo(DOZE_AOD, DOZE);
+ assertEquals(1f, mHostFake.aodDimmingScrimOpacity, 0.001f /* delta */);
+
+ mScreen.transitionTo(DOZE, DOZE_AOD);
+ mSensor.sendSensorEvent(2);
+ assertEquals(0f, mHostFake.aodDimmingScrimOpacity, 0.001f /* delta */);
+ }
+
+ @Test
public void pausingAod_unblanksAfterSensor() throws Exception {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
index beba905..87ae85f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
@@ -45,12 +45,11 @@
private DozeWallpaperState mDozeWallpaperState;
@Mock IWallpaperManager mIWallpaperManager;
@Mock DozeParameters mDozeParameters;
- @Mock DozeMachine mMachine;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mDozeWallpaperState = new DozeWallpaperState(mMachine, mIWallpaperManager, mDozeParameters);
+ mDozeWallpaperState = new DozeWallpaperState(mIWallpaperManager, mDozeParameters);
}
@Test
@@ -110,28 +109,18 @@
}
@Test
- public void testTransitionTo_notificationPulseIsAmbientMode() throws RemoteException {
- when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_NOTIFICATION);
- mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
- DozeMachine.State.DOZE_PULSING);
- verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(0L));
- }
-
- @Test
public void testTransitionTo_wakeFromPulseIsNotAmbientMode() throws RemoteException {
- when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN);
mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD,
DozeMachine.State.DOZE_REQUEST_PULSE);
reset(mIWallpaperManager);
mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
- DozeMachine.State.DOZE_PULSING);
+ DozeMachine.State.DOZE_PULSING_BRIGHT);
verify(mIWallpaperManager).setInAmbientMode(eq(false), anyLong());
}
@Test
public void testTransitionTo_animatesWhenWakingUpFromPulse() throws RemoteException {
- when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_NOTIFICATION);
mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
DozeMachine.State.DOZE_PULSING);
reset(mIWallpaperManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index f51e473..5928a07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -265,6 +265,12 @@
state.mIsPowerSaver = true;
shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
assertThat(shouldShow).isFalse();
+
+ state.mIsPowerSaver = false;
+ // if disabled we should not show the low warning.
+ state.mIsLowLevelWarningEnabled = false;
+ shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
+ assertThat(shouldShow).isFalse();
}
@Test
@@ -365,7 +371,7 @@
assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_HYBRID_THRESHOLD);
BatteryStateSnapshot snapshot = new BatteryStateSnapshot(
BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD,
- 0, 0, -1, 0, 0, false);
+ 0, 0, -1, 0, 0, false, true);
mPowerUI.mLastBatteryStateSnapshot = snapshot;
// query again since the estimate was -1
@@ -375,7 +381,7 @@
assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD);
snapshot = new BatteryStateSnapshot(
BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD, 0,
- 0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, false);
+ 0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, false, true);
mPowerUI.mLastBatteryStateSnapshot = snapshot;
// Battery level hasn't changed, so we don't query again
@@ -536,13 +542,14 @@
public long mTimeRemainingMillis = Duration.ofHours(24).toMillis();
public boolean mIsBasedOnUsage = true;
public boolean mIsHybrid = true;
+ public boolean mIsLowLevelWarningEnabled = true;
public BatteryStateSnapshot get() {
if (mIsHybrid) {
return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket,
mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold,
mTimeRemainingMillis, mSevereThresholdMillis, mLowThresholdMillis,
- mIsBasedOnUsage);
+ mIsBasedOnUsage, mIsLowLevelWarningEnabled);
} else {
return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket,
mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index fd31013..47933ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -194,7 +194,7 @@
VPN_PACKAGE),
mFooterText.getText());
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
// Same situation, but with organization name set
when(mSecurityController.getDeviceOwnerOrganizationName())
@@ -220,7 +220,7 @@
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_vpns),
mFooterText.getText());
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
// Same situation, but with organization name set
when(mSecurityController.getDeviceOwnerOrganizationName())
@@ -243,7 +243,7 @@
TestableLooper.get(this).processAllMessages();
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
mFooterText.getText());
}
@@ -294,7 +294,7 @@
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
- assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
assertEquals(mContext.getString(R.string.quick_settings_disclosure_vpns),
mFooterText.getText());
}
@@ -306,7 +306,7 @@
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
- assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
assertEquals(mContext.getString(
R.string.quick_settings_disclosure_managed_profile_named_vpn,
VPN_PACKAGE_2),
@@ -320,7 +320,7 @@
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
- assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+ assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
assertEquals(mContext.getString(R.string.quick_settings_disclosure_named_vpn,
VPN_PACKAGE),
mFooterText.getText());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 8c5f6f2..5ea4636 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -212,7 +212,7 @@
*
* @return a notification with no special properties
*/
- private Notification createNotification() {
+ public Notification createNotification() {
return createNotification(false /* isGroupSummary */, null /* groupKey */);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 0aa103f..8077e3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -37,7 +37,9 @@
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
+import android.app.Notification;
import android.app.NotificationChannel;
+import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -355,4 +357,30 @@
mGroupRow.setUserExpanded(true);
Assert.assertTrue(mGroupRow.isExpanded());
}
+
+ @Test
+ public void testGetIsNonblockable() throws Exception {
+ ExpandableNotificationRow row =
+ mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
+
+ assertFalse(row.getIsNonblockable());
+ }
+
+ @Test
+ public void testGetIsNonblockable_oemLocked() throws Exception {
+ ExpandableNotificationRow row =
+ mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
+ row.getEntry().channel.setImportanceLockedByOEM(true);
+
+ assertTrue(row.getIsNonblockable());
+ }
+
+ @Test
+ public void testGetIsNonblockable_criticalDeviceFunction() throws Exception {
+ ExpandableNotificationRow row =
+ mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
+ row.getEntry().channel.setImportanceLockedByCriticalDeviceFunction(true);
+
+ assertTrue(row.getIsNonblockable());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 539851f..191c983 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -46,7 +46,6 @@
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.util.function.TriConsumer;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.util.wakelock.WakeLock;
import com.android.systemui.utils.os.FakeHandler;
@@ -140,7 +139,6 @@
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
// Pulsing notification should conserve AOD wallpaper.
- mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
mScrimController.transitionTo(ScrimState.PULSING);
mScrimController.finishAnimationsImmediately();
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
@@ -225,14 +223,17 @@
mScrimController.finishAnimationsImmediately();
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
- mScrimController.setPulseReason(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN);
mScrimController.transitionTo(ScrimState.PULSING);
mScrimController.finishAnimationsImmediately();
// Front scrim should be transparent
// Back scrim should be semi-transparent so the user can see the wallpaper
// Pulse callback should have been invoked
- assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
+ assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
assertScrimTint(mScrimBehind, true /* tinted */);
+
+ mScrimController.setWakeLockScreenSensorActive(true);
+ mScrimController.finishAnimationsImmediately();
+ assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
}
@Test
@@ -486,7 +487,6 @@
@Test
public void testHoldsPulsingWallpaperAnimationLock() {
// Pre-conditions
- mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
mScrimController.transitionTo(ScrimState.PULSING);
mScrimController.finishAnimationsImmediately();
reset(mWakeLock);
@@ -508,30 +508,6 @@
}
@Test
- public void testWillHidePulsingWallpaper_whenNotification() {
- mScrimController.setWallpaperSupportsAmbientMode(false);
- mScrimController.transitionTo(ScrimState.AOD);
- mScrimController.finishAnimationsImmediately();
- mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
- mScrimController.transitionTo(ScrimState.PULSING);
- mScrimController.finishAnimationsImmediately();
- assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
- assertScrimTint(mScrimBehind, true);
- }
-
- @Test
- public void testWillHidePulsingWallpaper_whenDocking() {
- mScrimController.setWallpaperSupportsAmbientMode(false);
- mScrimController.transitionTo(ScrimState.AOD);
- mScrimController.finishAnimationsImmediately();
- mScrimController.setPulseReason(DozeLog.PULSE_REASON_DOCKING);
- mScrimController.transitionTo(ScrimState.PULSING);
- mScrimController.finishAnimationsImmediately();
- assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
- assertScrimTint(mScrimBehind, true);
- }
-
- @Test
public void testConservesExpansionOpacityAfterTransition() {
mScrimController.transitionTo(ScrimState.UNLOCKED);
mScrimController.setPanelExpansion(0.5f);
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index 72ce9c4..989470f 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -29,6 +29,7 @@
import android.text.Html;
import android.text.Html.ImageGetter;
import android.util.Log;
+import android.util.TypedValue;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
@@ -111,8 +112,16 @@
@Override
public Drawable getDrawable(String source) {
// Should only reach this when fetching the VPN icon for the warning string.
- Drawable icon = getDrawable(R.drawable.ic_vpn_dialog);
+ final Drawable icon = getDrawable(R.drawable.ic_vpn_dialog);
icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
+
+ final TypedValue tv = new TypedValue();
+ if (getTheme().resolveAttribute(android.R.attr.textColorPrimary, tv, true)) {
+ icon.setTint(getColor(tv.resourceId));
+ } else {
+ Log.w(TAG, "Unable to resolve theme color");
+ }
+
return icon;
}
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
new file mode 100644
index 0000000..5f7d519
--- /dev/null
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
@@ -0,0 +1,27 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="@*android:color/accent_device_default"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.12,7.38c0-2.96-2.41-5.38-5.37-5.38H11v7.94L6.03,4.97c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12 l-5.97,5.97c-0.29,0.29-0.29,0.77,0,1.06c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22L11,14.06V22h0.75 c2.96,0,5.37-2.41,5.37-5.38c0-1.97-1.06-3.69-2.64-4.62C16.06,11.06,17.12,9.34,17.12,7.38z M15.62,16.62 c0,1.88-1.34,3.45-3.12,3.8v-7.6C14.28,13.17,15.62,14.75,15.62,16.62z M12.5,11.18v-7.6c1.78,0.35,3.12,1.92,3.12,3.8 S14.28,10.83,12.5,11.18z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_invert_colors.xml
deleted file mode 100644
index 59e7838..0000000
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM12,21a6.92,6.92,0,0,1-7-7C5,9.16,9.89,4.71,12,3Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_airplane.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_airplane.xml
new file mode 100644
index 0000000..9743ceb
--- /dev/null
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_airplane.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="18dp"
+ android:height="18dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,15.89v-2.57c0-1.1-0.65-2.09-1.67-2.53L14.5,8.28V3.75c0-1.38-1.12-2.5-2.5-2.5s-2.5,1.12-2.5,2.5v4.53l-5.83,2.51 C2.65,11.22,2,12.22,2,13.32v2.57l7.5-1.28v3.03l-1.47,1.17C7.38,19.34,7,20.12,7,20.96v1.33l4.96-0.3L17,22.3v-1.33 c0-0.84-0.38-1.62-1.03-2.15l-1.47-1.17v-3.03L22,15.89z M15.03,19.98c0.23,0.18,0.38,0.44,0.44,0.72l-3.52-0.2l-3.43,0.2 c0.06-0.28,0.21-0.53,0.44-0.72L11,18.36v-5.53l-7.5,1.28v-0.79c0-0.5,0.3-0.95,0.76-1.15L11,9.27V3.75c0-0.55,0.45-1,1-1 s1,0.45,1,1v5.52l6.74,2.9c0.46,0.2,0.76,0.65,0.76,1.15v0.79L13,12.83v5.53L15.03,19.98z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
new file mode 100644
index 0000000..8dfa4a4
--- /dev/null
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
@@ -0,0 +1,29 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M2.75,6.5v4.75H7.5c0.41,0,0.75-0.34,0.75-0.75S7.91,9.75,7.5,9.75H5.39l4.5-4.22c0.89-0.84,2.27-0.82,3.13,0.05l4.94,4.95 c0.29,0.29,0.77,0.29,1.06,0c0.29-0.29,0.29-0.77,0-1.06l-4.94-4.95c-1.44-1.44-3.73-1.48-5.22-0.08L4.25,8.77V6.5 c0-0.41-0.34-0.75-0.75-0.75S2.75,6.09,2.75,6.5z" />
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21.25,17.5v-4.75H16.5c-0.41,0-0.75,0.34-0.75,0.75s0.34,0.75,0.75,0.75h2.11l-4.5,4.22c-0.89,0.84-2.27,0.82-3.13-0.05 l-4.94-4.95c-0.29-0.29-0.77-0.29-1.06,0c-0.29,0.29-0.29,0.77,0,1.06l4.94,4.95c0.74,0.74,1.69,1.11,2.65,1.11 c0.92,0,1.84-0.34,2.57-1.02l4.62-4.33v2.27c0,0.41,0.34,0.75,0.75,0.75S21.25,17.91,21.25,17.5z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
similarity index 60%
copy from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
copy to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
index 173824b..c12a2eb 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
@@ -21,8 +21,6 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M17.12,7.38c0-2.96-2.41-5.38-5.37-5.38H11v7.94L6.03,4.97c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12 l-5.97,5.97c-0.29,0.29-0.29,0.77,0,1.06c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22L11,14.06V22h0.75 c2.96,0,5.37-2.41,5.37-5.38c0-1.97-1.06-3.69-2.64-4.62C16.06,11.06,17.12,9.34,17.12,7.38z M15.62,16.62 c0,1.88-1.34,3.45-3.12,3.8v-7.6C14.28,13.17,15.62,14.75,15.62,16.62z M12.5,11.18v-7.6c1.78,0.35,3.12,1.92,3.12,3.8 S14.28,10.83,12.5,11.18z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_dnd.xml
similarity index 60%
copy from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
copy to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_dnd.xml
index 173824b..d364646 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_dnd.xml
@@ -15,14 +15,15 @@
*/
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="17dp"
+ android:height="17dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M12,22c5.52,0,10-4.48,10-10c0-5.52-4.48-10-10-10S2,6.48,2,12C2,17.52,6.48,22,12,22z M12,3.5c4.69,0,8.5,3.81,8.5,8.5 c0,4.69-3.81,8.5-8.5,8.5S3.5,16.69,3.5,12C3.5,7.31,7.31,3.5,12,3.5z" />
<path
- android:fillColor="#000000"
- android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M6.75,12.75h10.5c0.41,0,0.75-0.34,0.75-0.75s-0.34-0.75-0.75-0.75H6.75C6.34,11.25,6,11.59,6,12S6.34,12.75,6.75,12.75z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_flashlight.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_flashlight.xml
similarity index 67%
rename from packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
rename to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_flashlight.xml
index 1526691..cce36e3 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_flashlight.xml
@@ -21,13 +21,9 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M11,22h2c1.1,0,2-0.9,2-2V10c1.95-1.17,3-3.5,3-6V3H6v1c0,2.5,1.05,4.83,3,6v10C9,21.1,9.9,22,11,22z M16.48,4.5 C16.45,5.03,16.35,5.53,16.2,6H7.8C7.65,5.53,7.55,5.03,7.52,4.5H16.48z M8.51,7.5h6.99c-0.35,0.5-0.77,0.92-1.26,1.21L13.5,9.15 V20c0,0.28-0.22,0.5-0.5,0.5h-2c-0.28,0-0.5-0.22-0.5-0.5V9.15L9.77,8.71C9.28,8.42,8.85,8,8.51,7.5z" />
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M11,22h2a2,2,0,0,0,2-2V10a6.84,6.84,0,0,0,3-6V3H6V4a6.84,6.84,0,0,0,3,6V20A2,2,0,0,0,11,22ZM17,4a8.26,8.26,0,0,1-0.07,1H7.07A8.26,8.26,0,0,1,7,4ZM7.28,6h9.45a5.24,5.24,0,0,1-2.24,3.14L14,9.43V20a1,1,0,0,1-1,1H11a1,1,0,0,1-1-1V9.43l-0.49-0.29A5.25,5.25,0,0,1,7.28,6Z" />
- <path
- android:fillColor="#000000"
+ android:fillColor="@android:color/white"
android:pathData="M 12 13 C 12.5522847498 13 13 13.4477152502 13 14 C 13 14.5522847498 12.5522847498 15 12 15 C 11.4477152502 15 11 14.5522847498 11 14 C 11 13.4477152502 11.4477152502 13 12 13 Z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
similarity index 60%
copy from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
copy to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
index 173824b..c12a2eb 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
@@ -21,8 +21,6 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M17.12,7.38c0-2.96-2.41-5.38-5.37-5.38H11v7.94L6.03,4.97c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12 l-5.97,5.97c-0.29,0.29-0.29,0.77,0,1.06c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22L11,14.06V22h0.75 c2.96,0,5.37-2.41,5.37-5.38c0-1.97-1.06-3.69-2.64-4.62C16.06,11.06,17.12,9.34,17.12,7.38z M15.62,16.62 c0,1.88-1.34,3.45-3.12,3.8v-7.6C14.28,13.17,15.62,14.75,15.62,16.62z M12.5,11.18v-7.6c1.78,0.35,3.12,1.92,3.12,3.8 S14.28,10.83,12.5,11.18z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml
new file mode 100644
index 0000000..8dbae49
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M22,15.89v-2.57c0-1.1-0.65-2.09-1.67-2.53L14.5,8.28V3.75c0-1.38-1.12-2.5-2.5-2.5s-2.5,1.12-2.5,2.5v4.53l-5.83,2.51 C2.65,11.22,2,12.22,2,13.32v2.57l7.5-1.28v3.03l-1.47,1.17C7.38,19.34,7,20.12,7,20.96v1.33l4.96-0.3L17,22.3v-1.33 c0-0.84-0.38-1.62-1.03-2.15l-1.47-1.17v-3.03L22,15.89z M15.03,19.98c0.23,0.18,0.38,0.44,0.44,0.72l-3.52-0.2l-3.43,0.2 c0.06-0.28,0.21-0.53,0.44-0.72L11,18.36v-5.53l-7.5,1.28v-0.79c0-0.5,0.3-0.95,0.76-1.15L11,9.27V3.75c0-0.55,0.45-1,1-1 s1,0.45,1,1v5.52l6.74,2.9c0.46,0.2,0.76,0.65,0.76,1.15v0.79L13,12.83v5.53L15.03,19.98z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dnd.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dnd.xml
deleted file mode 100644
index 3e32b3b..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dnd.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12,22A10,10,0,1,0,2,12,10,10,0,0,0,12,22ZM12,3a9,9,0,1,1-9,9A9,9,0,0,1,12,3Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M7,12.5H17a0.5 0.5 ,0,0,0,0-1H7a0.5 0.5 ,0,0,0,0,1Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
deleted file mode 100644
index 04a2c24..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M21,21a2,2,0,0,0,2-2V6a2,2,0,0,0-2-2H3A2,2,0,0,0,1,6V19a2,2,0,0,0,2,2ZM2,19V6A1,1,0,0,1,3,5H21a1,1,0,0,1,1,1V19a1,1,0,0,1-1,1H3A1,1,0,0,1,2,19Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 9.5 8 L 10.5 8 Q 11 8 11 8.5 L 11 9.5 Q 11 10 10.5 10 L 9.5 10 Q 9 10 9 9.5 L 9 8.5 Q 9 8 9.5 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 5.5 8 L 6.5 8 Q 7 8 7 8.5 L 7 9.5 Q 7 10 6.5 10 L 5.5 10 Q 5 10 5 9.5 L 5 8.5 Q 5 8 5.5 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 13.5 8 L 14.5 8 Q 15 8 15 8.5 L 15 9.5 Q 15 10 14.5 10 L 13.5 10 Q 13 10 13 9.5 L 13 8.5 Q 13 8 13.5 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 9.5 12 L 10.5 12 Q 11 12 11 12.5 L 11 13.5 Q 11 14 10.5 14 L 9.5 14 Q 9 14 9 13.5 L 9 12.5 Q 9 12 9.5 12 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 5.5 12 L 6.5 12 Q 7 12 7 12.5 L 7 13.5 Q 7 14 6.5 14 L 5.5 14 Q 5 14 5 13.5 L 5 12.5 Q 5 12 5.5 12 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 13.5 12 L 14.5 12 Q 15 12 15 12.5 L 15 13.5 Q 15 14 14.5 14 L 13.5 14 Q 13 14 13 13.5 L 13 12.5 Q 13 12 13.5 12 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 17.5 8 L 18.5 8 Q 19 8 19 8.5 L 19 9.5 Q 19 10 18.5 10 L 17.5 10 Q 17 10 17 9.5 L 17 8.5 Q 17 8 17.5 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 17.5 12 L 18.5 12 Q 19 12 19 12.5 L 19 13.5 Q 19 14 18.5 14 L 17.5 14 Q 17 14 17 13.5 L 17 12.5 Q 17 12 17.5 12 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M8.5,17h7a0.5 0.5 ,0,0,0,0-1h-7a0.5 0.5 ,0,0,0,0,1Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
deleted file mode 100644
index f98e2b8..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M3.5,6a0.5 0.5 ,0,0,0-0.5 0.5 V11H7.5a0.5 0.5 ,0,0,0,0-1H4.76l5-4.65a2.49,2.49,0,0,1,3.48 0.05 l4.95,4.95a0.49 0.49 ,0,1,0,0.7-0.7L13.91,4.7A3.47,3.47,0,0,0,9,4.62L4,9.35V6.5A0.5 0.5 ,0,0,0,3.5,6Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M20.5,18a0.5 0.5 ,0,0,0,0.5-0.5V13H16.5a0.5 0.5 ,0,0,0,0,1h2.74l-5,4.65a2.49,2.49,0,0,1-3.48,0l-5-5a0.49 0.49 ,0,0,0-0.7 0.7 l4.94,5a3.47,3.47,0,0,0,4.87 0.08 l5-4.73V17.5A0.5 0.5 ,0,0,0,20.5,18Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
deleted file mode 100644
index fc990d8..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M3.41,14.72A2,2,0,0,1,4,16.14V18a2,2,0,0,0,2,2H7.86a2,2,0,0,1,1.42 0.59 l1.31,1.31a2,2,0,0,0,2.82,0l1.31-1.31A2,2,0,0,1,16.14,20H18a2,2,0,0,0,2-2V16.14a2,2,0,0,1,0.59-1.42l1.31-1.31a2,2,0,0,0,0-2.82L20.59,9.28A2,2,0,0,1,20,7.86V6a2,2,0,0,0-2-2H16.14a2,2,0,0,1-1.42-0.59L13.41,2.1a2,2,0,0,0-2.82,0L9.28,3.41A2,2,0,0,1,7.86,4H6A2,2,0,0,0,4,6V7.86a2,2,0,0,1-0.59,1.42L2.1,10.59a2,2,0,0,0,0,2.82Zm-0.6-3.43L4.12,10A3,3,0,0,0,5,7.86V6A1,1,0,0,1,6,5H7.86A3,3,0,0,0,10,4.12l1.31-1.31a1,1,0,0,1,1.42,0L14,4.12A3,3,0,0,0,16.14,5H18a1,1,0,0,1,1,1V7.86A3,3,0,0,0,19.88,10l1.31,1.31a1,1,0,0,1,0,1.42L19.88,14A3,3,0,0,0,19,16.14V18a1,1,0,0,1-1,1H16.14a3,3,0,0,0-2.12 0.88 l-1.31,1.31a1,1,0,0,1-1.42,0L10,19.88A3,3,0,0,0,7.86,19H6a1,1,0,0,1-1-1V16.14A3,3,0,0,0,4.12,14L2.81,12.71a1,1,0,0,1,0-1.42Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M10,14.61h4L14.85,17H17L13.11,7H10.87L7,17H9.15Zm1.92-5.44h0.11l1.29,3.71H10.63Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_cast_on.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
deleted file mode 100644
index d12cf9e..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M22,17.5V6.5A2.5,2.5,0,0,0,19.5,4H4.5A2.5,2.5,0,0,0,2,6.5v2a0.5 0.5 ,0,0,0,1,0v-2A1.5,1.5,0,0,1,4.5,5h15A1.5,1.5,0,0,1,21,6.5v11A1.5,1.5,0,0,1,19.5,19h-6a0.5 0.5 ,0,0,0,0,1h6A2.5,2.5,0,0,0,22,17.5Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M2.21,19.61A1,1,0,0,0,3,20a1,1,0,0,0,0-2H3a1,1,0,0,0-0.79,1.61Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M2.5,12A7.5,7.5,0,0,1,10,19.5a0.5 0.5 ,0,0,0,1,0A8.51,8.51,0,0,0,2.5,11a0.5 0.5 ,0,0,0,0,1Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M2.5,16A3.5,3.5,0,0,1,6,19.5a0.5 0.5 ,0,0,0,1,0A4.51,4.51,0,0,0,2.5,15a0.5 0.5 ,0,0,0,0,1Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M16.5,15h-3a0.5 0.5 ,0,0,0,0,1h3A1.5,1.5,0,0,0,18,14.5v-5A1.5,1.5,0,0,0,16.5,8H6.5a0.5 0.5 ,0,0,0,0,1h10a0.5 0.5 ,0,0,1,0.5 0.5 v5A0.5 0.5 ,0,0,1,16.5,15Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_settings_16dp.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_settings_16dp.xml
deleted file mode 100644
index 33d172c..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_settings_16dp.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="16dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M5.31,19.26a1.6,1.6,0,0,0,0.53-0.09l1.8-0.7c0.26 0.16 0.52 0.31 0.79 0.45 l0.27,1.84A1.44,1.44,0,0,0,10.15,22h3.7a1.46,1.46,0,0,0,1.46-1.19l0.27-1.87c0.26-0.13 0.52 -0.28 0.78 -0.44l1.8 0.7 a1.47,1.47,0,0,0,0.54 0.1 A1.44,1.44,0,0,0,20,18.58l1.86-3.14a1.4,1.4,0,0,0-0.37-1.81l-1.52-1.17c0-0.14,0-0.29,0-0.45s0-0.3,0-0.44l1.52-1.17a1.41,1.41,0,0,0,0.36-1.83L20,5.47a1.46,1.46,0,0,0-1.29-0.73,1.69,1.69,0,0,0-0.53 0.09 l-1.8 0.7 c-0.26-0.16-0.52-0.31-0.79-0.45l-0.27-1.84A1.44,1.44,0,0,0,13.84,2h-3.7A1.45,1.45,0,0,0,8.7,3.22L8.43,5.08q-0.39 0.21 -0.78 0.45 L5.84,4.82a1.47,1.47,0,0,0-0.54-0.1,1.43,1.43,0,0,0-1.25 0.72 L2.2,8.55a1.37,1.37,0,0,0,0.37,1.83l1.52,1.17c0,0.14,0,0.3,0,0.45s0,0.3,0,0.44L2.56,13.61a1.42,1.42,0,0,0-0.36,1.83L4,18.53A1.46,1.46,0,0,0,5.31,19.26ZM3.16,14.4l1.53-1.16 0.43 -0.33,0-0.53c0-0.13,0-0.25,0-0.38s0-0.26,0-0.39l0-0.53-0.42-0.33L3.17,9.58a0.38 0.38 ,0,0,1-0.11-0.52L4.92,5.93a0.43 0.43 ,0,0,1,0.38-0.21 0.47 0.47,0,0,1,0.17,0l1.81 0.71 0.48 0.19 0.43-0.27A6.39,6.39,0,0,1,8.9,6l0.45-0.24 0.07 -0.5 0.27 -1.88A0.44 0.44 ,0,0,1,10.14,3h3.7a0.44 0.44 ,0,0,1,0.46 0.38 l0.27,1.85 0.08 0.51 0.46 0.24a5.3,5.3,0,0,1,0.7 0.4 l0.43 0.27 0.47-0.19,1.78-0.69a0.63 0.63 ,0,0,1,0.19,0,0.47 0.47 ,0,0,1,0.43 0.24 l1.83,3.08a0.42 0.42 ,0,0,1-0.1 0.55 l-1.52,1.16-0.42 0.33 ,0,0.53c0,0.13,0,0.25,0,0.38s0,0.26,0,0.39l0,0.53 0.42 0.33,1.51,1.15a0.42 0.42 ,0,0,1,0.13 0.52 l-1.87,3.16a0.43 0.43 ,0,0,1-0.39 0.21 0.57 0.57 ,0,0,1-0.18,0l-1.8-0.71-0.47-0.18-0.43 0.27 a7.46,7.46,0,0,1-0.71 0.41 l-0.45 0.24 -0.07 0.5 -0.27,1.86a0.47 0.47 ,0,0,1-0.47 0.34 h-3.7a0.44 0.44 ,0,0,1-0.46-0.38l-0.27-1.85-0.08-0.51L8.88,18a5.3,5.3,0,0,1-0.7-0.4l-0.43-0.27-0.47 0.19 -1.78 0.69 a0.58 0.58 ,0,0,1-0.19,0A0.48 0.48 ,0,0,1,4.89,18L3.08,15A0.42 0.42 ,0,0,1,3.16,14.4Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12,15.91A3.92,3.92,0,1,0,8,12,4,4,0,0,0,12,15.91Zm0-6.83A2.92,2.92,0,1,1,9,12,3,3,0,0,1,12,9.08Z" />
-</vector>
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_airplane.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_airplane.xml
deleted file mode 100644
index a5ef380..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_airplane.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M2.8,15l7.2-0.73v3.49L8,19.38a1.52,1.52,0,0,0-0.54,1.16v1a0.52 0.52 ,0,0,0,0.17 0.38 0.51 0.51 ,0,0,0,0.39 0.12 L12,21.5l3.94 0.5 H16a0.5 0.5 ,0,0,0,0.33-0.12 0.52 0.52,0,0,0,0.17-0.38v-1A1.52,1.52,0,0,0,16,19.38l-2-1.62V14.27l7.2 0.73 a0.51 0.51 ,0,0,0,0.55-0.5,3.49,3.49,0,0,0-2.15-3.23L14,8.94V3.5a2,2,0,0,0-4,0V8.94L4.4,11.27A3.49,3.49,0,0,0,2.25,14.5a0.51 0.51 ,0,0,0,0.55 0.5 Zm2-2.81,5.9-2.45A0.5 0.5 ,0,0,0,11,9.28V3.5a1,1,0,0,1,2,0V9.28a0.5 0.5 ,0,0,0,0.31 0.46 l5.9,2.45a2.51,2.51,0,0,1,1.48,1.75l-7.14-0.72a0.52 0.52 ,0,0,0-0.38 0.13 0.5 0.5 ,0,0,0-0.17 0.37 V18a0.53 0.53 ,0,0,0,0.18 0.39 l2.14,1.76a0.53 0.53 ,0,0,1,0.18 0.39 v0.39l-3.44-0.43h-0.12l-3.44 0.43 v-0.39a0.53 0.53 ,0,0,1,0.18-0.39l2.14-1.76A0.53 0.53 ,0,0,0,11,18V13.72a0.5 0.5 ,0,0,0-0.17-0.37 0.52 0.52,0,0,0-0.38-0.13l-7.14 0.72 A2.51,2.51,0,0,1,4.79,12.19Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
new file mode 100644
index 0000000..c5c3f06
--- /dev/null
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
@@ -0,0 +1,27 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="@*android:color/accent_device_default"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.21,6.79l-4.5-4.5c-0.29-0.29-0.72-0.37-1.09-0.22C11.25,2.23,11,2.6,11,3v6.59l-3.8-3.8c-0.39-0.39-1.02-0.39-1.41,0 c-0.39,0.39-0.39,1.02,0,1.41l4.8,4.8l-4.8,4.8c-0.39,0.39-0.39,1.02,0,1.41c0.39,0.39,1.02,0.39,1.41,0l3.8-3.8V21 c0,0.4,0.24,0.77,0.62,0.92C11.74,21.98,11.87,22,12,22c0.26,0,0.52-0.1,0.71-0.29l4.5-4.5c0.39-0.39,0.39-1.02,0-1.41L13.42,12 l3.79-3.79C17.6,7.82,17.6,7.18,17.21,6.79z M15.09,16.5L13,18.58v-4.17L15.09,16.5z M13,9.58V5.42l2.08,2.08L13,9.58z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_airplane.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_airplane.xml
new file mode 100644
index 0000000..85260c0
--- /dev/null
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_airplane.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="18dp"
+ android:height="18dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M2.65,15.8L10,13.5V19l-1.6,1.2C8.15,20.39,8,20.69,8,21v0.67c0,0.17,0.14,0.28,0.31,0.24c1.94-0.55,1.3-0.37,3.19-0.91 c1.21,0.35,1.99,0.57,3.19,0.91c0.17,0.04,0.31-0.07,0.31-0.24V21c0-0.31-0.15-0.61-0.4-0.8L13,19v-5.5l7.35,2.3 c0.32,0.1,0.65-0.14,0.65-0.48v-0.49c0-0.52-0.27-1-0.7-1.27L13,9V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-7.3,4.56 C2.27,13.83,2,14.31,2,14.83v0.49C2,15.66,2.33,15.9,2.65,15.8z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
similarity index 60%
rename from packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
rename to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
index f823812..bcdb618 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
@@ -21,11 +21,9 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M16.41,10.96h2.83l-8.18-8.18c-0.62-0.62-1.65-0.6-2.29,0.04L4.27,7.31L2.85,5.89C2.54,5.58,2,5.8,2,6.25v4.25 C2,10.78,2.22,11,2.5,11h4.25c0.45,0,0.67-0.54,0.35-0.85L5.69,8.73l4.24-4.24L16.41,10.96z" />
<path
- android:fillColor="#000000"
- android:pathData="M16.41,11h2.83L11.05,2.78a1.62,1.62,0,0,0-2.29,0L4.27,7.31,2.85,5.89A0.5 0.5 ,0,0,0,2,6.25V10.5a0.5 0.5 ,0,0,0,0.5 0.5 H6.75a0.5 0.5 ,0,0,0,0.36-0.85L5.69,8.73,9.93,4.49Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M22,13.51a0.5 0.5 ,0,0,0-0.5-0.5H17.25a0.5 0.5 ,0,0,0-0.36 0.85 l1.35,1.35-4.31,4.31L7.44,13H4.61l8.19,8.18a1.62,1.62,0,0,0,2.29,0l4.57-4.55,1.49,1.49a0.5 0.5 ,0,0,0,0.85-0.36Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M22,13.51c0-0.28-0.22-0.5-0.5-0.5h-4.25c-0.45,0-0.67,0.54-0.35,0.85l1.34,1.34l-4.31,4.31l-6.48-6.48H4.61l8.19,8.19 c0.62,0.62,1.65,0.6,2.29-0.04l4.57-4.55l1.49,1.49c0.32,0.31,0.85,0.09,0.85-0.35V13.51z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
similarity index 60%
copy from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
copy to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
index 173824b..cf7cab5 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
@@ -21,8 +21,6 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M17.21,6.79l-4.5-4.5c-0.29-0.29-0.72-0.37-1.09-0.22C11.25,2.23,11,2.6,11,3v6.59l-3.8-3.8c-0.39-0.39-1.02-0.39-1.41,0 c-0.39,0.39-0.39,1.02,0,1.41l4.8,4.8l-4.8,4.8c-0.39,0.39-0.39,1.02,0,1.41c0.39,0.39,1.02,0.39,1.41,0l3.8-3.8V21 c0,0.4,0.24,0.77,0.62,0.92C11.74,21.98,11.87,22,12,22c0.26,0,0.52-0.1,0.71-0.29l4.5-4.5c0.39-0.39,0.39-1.02,0-1.41L13.42,12 l3.79-3.79C17.6,7.82,17.6,7.18,17.21,6.79z M15.09,16.5L13,18.58v-4.17L15.09,16.5z M13,9.58V5.42l2.08,2.08L13,9.58z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dnd.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_dnd.xml
similarity index 72%
rename from packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dnd.xml
rename to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_dnd.xml
index e6086f3..a094698 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dnd.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_dnd.xml
@@ -15,14 +15,12 @@
*/
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="17dp"
+ android:height="17dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12,22A10,10,0,1,0,2,12,10,10,0,0,0,12,22ZM8,11h8a1,1,0,0,1,0,2H8a1,1,0,0,1,0-2Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M12,22c5.52,0,10-4.48,10-10c0-5.52-4.48-10-10-10S2,6.48,2,12C2,17.52,6.48,22,12,22z M8,11h8c0.55,0,1,0.45,1,1 s-0.45,1-1,1H8c-0.55,0-1-0.45-1-1S7.45,11,8,11z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_flashlight.xml
similarity index 68%
rename from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
rename to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_flashlight.xml
index 173824b..4427305 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_flashlight.xml
@@ -21,8 +21,9 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M10,22h4c0.55,0,1-0.45,1-1V10c1.1,0,2-0.9,2-2V5.5H7V8c0,1.1,0.9,2,2,2v11C9,21.55,9.45,22,10,22z M11,12 c0-0.55,0.45-1,1-1s1,0.45,1,1v2c0,0.55-0.45,1-1,1s-1-0.45-1-1V12z" />
<path
- android:fillColor="#000000"
- android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M17,3c0-0.55-0.45-1-1-1H8C7.45,2,7,2.45,7,3v0.96h10V3z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
similarity index 60%
rename from packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_invert_colors.xml
rename to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
index 0564c73..cf7cab5 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
@@ -21,8 +21,6 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M17.44,7.71,12.7,3a1,1,0,0,0-1.41,0h0L6.56,7.71a8.21,8.21,0,0,0-0.62,11.1,8,8,0,0,0,12.12,0A8.21,8.21,0,0,0,17.44,7.71ZM12,19.59A6,6,0,0,1,7.76,9.35L12,5.1Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M17.21,6.79l-4.5-4.5c-0.29-0.29-0.72-0.37-1.09-0.22C11.25,2.23,11,2.6,11,3v6.59l-3.8-3.8c-0.39-0.39-1.02-0.39-1.41,0 c-0.39,0.39-0.39,1.02,0,1.41l4.8,4.8l-4.8,4.8c-0.39,0.39-0.39,1.02,0,1.41c0.39,0.39,1.02,0.39,1.41,0l3.8-3.8V21 c0,0.4,0.24,0.77,0.62,0.92C11.74,21.98,11.87,22,12,22c0.26,0,0.52-0.1,0.71-0.29l4.5-4.5c0.39-0.39,0.39-1.02,0-1.41L13.42,12 l3.79-3.79C17.6,7.82,17.6,7.18,17.21,6.79z M15.09,16.5L13,18.58v-4.17L15.09,16.5z M13,9.58V5.42l2.08,2.08L13,9.58z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
similarity index 62%
copy from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
copy to packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
index 173824b..bddc57e 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -21,8 +21,6 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M2.65,15.8L10,13.5V19l-1.6,1.2C8.15,20.39,8,20.69,8,21v0.67c0,0.17,0.14,0.28,0.31,0.24c1.94-0.55,1.3-0.37,3.19-0.91 c1.21,0.35,1.99,0.57,3.19,0.91c0.17,0.04,0.31-0.07,0.31-0.24V21c0-0.31-0.15-0.61-0.4-0.8L13,19v-5.5l7.35,2.3 c0.32,0.1,0.65-0.14,0.65-0.48v-0.49c0-0.52-0.27-1-0.7-1.27L13,9V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-7.3,4.56 C2.27,13.83,2,14.31,2,14.83v0.49C2,15.66,2.33,15.9,2.65,15.8z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
deleted file mode 100644
index 8b9f562..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M3,21H21a2,2,0,0,0,2-2V6a2,2,0,0,0-2-2H3A2,2,0,0,0,1,6V19A2,2,0,0,0,3,21ZM3,6H21V19H3Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 9 8 H 11 V 10 H 9 V 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 5 8 H 7 V 10 H 5 V 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 8 16 H 16 V 17 H 8 V 16 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 13 8 H 15 V 10 H 13 V 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 9 12 H 11 V 14 H 9 V 12 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 5 12 H 7 V 14 H 5 V 12 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 13 12 H 15 V 14 H 13 V 12 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 17 8 H 19 V 10 H 17 V 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 17 12 H 19 V 14 H 17 V 12 Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
deleted file mode 100644
index f3b1c01..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M10,14.61h4L14.85,17H17L13.11,7H10.87L7,17H9.15Zm1.54-4.24 0.38 -1.2h0.11l0.38,1.2 0.91 ,2.51H10.63Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M4,20H8.69L12,23.31,15.31,20H20V15.31L23.31,12,20,8.69V4H15.31L12,0.69,8.69,4H4V8.69L0.69,12,4,15.31Zm-0.48-8L6,9.52V6H9.52L12,3.52,14.48,6H18V9.52L20.48,12,18,14.48V18H14.48L12,20.48,9.52,18H6V14.48Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_cast_on.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
deleted file mode 100644
index 0fd763b..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M1.82,16.08a5,5,0,0,1,4.1,4.08,1,1,0,0,0,1,0.84,1,1,0,0,0,1-1.14,7,7,0,0,0-5.8-5.78,1,1,0,0,0-0.29,2Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M19,7H5V8.63A13,13,0,0,1,13.37,17H19Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M3,5H21V19H14v2h7a2,2,0,0,0,2-2V5a2,2,0,0,0-2-2H3A2,2,0,0,0,1,5V8H3Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M1.85,12A9.06,9.06,0,0,1,10,20.12a1,1,0,0,0,1,0.88,1,1,0,0,0,1-1.1,11,11,0,0,0-9.87-9.85A1,1,0,0,0,1,11,1,1,0,0,0,1.85,12Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M2,21H4a3,3,0,0,0-3-3v2A1,1,0,0,0,2,21Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_settings_16dp.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_settings_16dp.xml
deleted file mode 100644
index d292b13..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_settings_16dp.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="16dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M21.64,8.39,20,5.63a1.12,1.12,0,0,0-1.36-0.5L16.54,6A7.26,7.26,0,0,0,15,5.12l-0.27-2.2A1.1,1.1,0,0,0,13.59,2H10.41a1.1,1.1,0,0,0-1.11 0.92 L9,5.11A7.1,7.1,0,0,0,7.46,6L5.32,5.12A1.12,1.12,0,0,0,4,5.62L2.36,8.38A1.1,1.1,0,0,0,2.6,9.8l1.94,1.45a6.06,6.06,0,0,0,0,0.75,6.34,6.34,0,0,0,0,0.76L2.6,14.2a1.09,1.09,0,0,0-0.24,1.41L4,18.37a1.12,1.12,0,0,0,1.36 0.5 L7.46,18A7.26,7.26,0,0,0,9,18.88l0.27,2.19a1.1,1.1,0,0,0,1.11 0.93 h3.18a1.11,1.11,0,0,0,1.11-0.92L15,18.89A7.26,7.26,0,0,0,16.54,18l2.14 0.91 a1.12,1.12,0,0,0,1.36-0.5l1.6-2.76a1.1,1.1,0,0,0-0.24-1.42l-1.94-1.45a7.24,7.24,0,0,0,0-1.52L21.4,9.8A1.09,1.09,0,0,0,21.64,8.39ZM12,15.5A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
-</vector>
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_airplane.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_airplane.xml
deleted file mode 100644
index 999a9bf..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_airplane.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M3.15,15.8l7.35-2.3V19L8.9,20.2a1,1,0,0,0-0.4 0.8 v0.67a0.24 0.24 ,0,0,0,0.31 0.24 L12,21l3.19 0.91 a0.24 0.24 ,0,0,0,0.31-0.24V21a1,1,0,0,0-0.4-0.8L13.5,19V13.5l7.35,2.3a0.5 0.5 ,0,0,0,0.65-0.48v-0.49a1.5,1.5,0,0,0-0.7-1.27L13.5,9V3.5a1.5,1.5,0,0,0-3,0V9L3.2,13.56a1.5,1.5,0,0,0-0.7,1.27v0.49A0.5 0.5 ,0,0,0,3.15,15.8Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_flashlight.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
deleted file mode 100644
index 1ffb32b..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M10,22h4a1,1,0,0,0,1-1V10a2,2,0,0,0,2-2V5.5H7V8a2,2,0,0,0,2,2V21A1,1,0,0,0,10,22Zm2-10a1.5,1.5,0,1,1-1.5,1.5A1.5,1.5,0,0,1,12,12Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M17,3a1,1,0,0,0-1-1H8A1,1,0,0,0,7,3V4H17Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
new file mode 100644
index 0000000..bd06e7c
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
@@ -0,0 +1,27 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="@*android:color/accent_device_default"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.53,6.72l-4.75-4.75c-0.21-0.21-0.54-0.28-0.82-0.16C11.68,1.92,11.5,2.2,11.5,2.5v7.69L7.53,6.22 c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L11.19,12l-4.72,4.72c-0.29,0.29-0.29,0.77,0,1.06s0.77,0.29,1.06,0l3.97-3.97v7.69 c0,0.3,0.18,0.58,0.46,0.69c0.09,0.04,0.19,0.06,0.29,0.06c0.2,0,0.39-0.08,0.53-0.22l4.75-4.75c0.29-0.29,0.29-0.77,0-1.06 L13.31,12l4.22-4.22C17.82,7.49,17.82,7.01,17.53,6.72z M15.94,16.75L13,19.69v-5.88L15.94,16.75z M13,10.19V4.31l2.94,2.94 L13,10.19z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_airplane.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_airplane.xml
new file mode 100644
index 0000000..5f9bdd2
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_airplane.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="18dp"
+ android:height="18dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M2.52,16.17c0.32,0.23,0.74,0.31,1.11,0.19l5.87-1.84v3.87L8,19.52c-0.31,0.24-0.5,0.61-0.5,1v0.75 c0,0.69,0.56,1.25,1.25,1.25h6.5c0.69,0,1.25-0.56,1.25-1.25v-0.75c0-0.39-0.19-0.76-0.5-1l-1.5-1.12v-3.87l5.88,1.84 c0.38,0.12,0.79,0.05,1.11-0.19c0.32-0.23,0.51-0.61,0.51-1.01l0-1.84c0-0.63-0.34-1.21-0.89-1.52L14.5,8.06V4 c0-1.38-1.12-2.5-2.5-2.5S9.5,2.62,9.5,4v4.07L2.89,11.8C2.35,12.11,2,12.7,2,13.33l0,1.83C2.01,15.56,2.2,15.94,2.52,16.17z M3.63,13.11L11,8.94V4c0-0.55,0.45-1,1-1s1,0.45,1,1v4.94l7.37,4.17c0.08,0.04,0.13,0.13,0.13,0.22l0,1.5L13,12.48v6.66l2,1.5 v0.38H9v-0.38l2-1.5v-6.66l-7.5,2.34l0-1.49C3.5,13.24,3.55,13.15,3.63,13.11z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
new file mode 100644
index 0000000..0f9effd
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
@@ -0,0 +1,29 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3.5,7C3.09,7,2.75,7.34,2.75,7.75v2.73c0,0.41,0.34,0.75,0.75,0.75h2.75c0.41,0,0.75-0.34,0.75-0.75S6.66,9.73,6.25,9.73 H5.33l5.42-5.42l6.47,6.47c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22c0.29-0.29,0.29-0.77,0-1.06l-7-7 c-0.29-0.29-0.77-0.29-1.06,0L4.25,8.69V7.75C4.25,7.34,3.91,7,3.5,7z" />
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.5,17c0.41,0,0.75-0.34,0.75-0.75V13.5c0-0.41-0.34-0.75-0.75-0.75h-2.75c-0.41,0-0.75,0.34-0.75,0.75 s0.34,0.75,0.75,0.75h0.94l-5.44,5.44l-6.47-6.47c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06l7,7 c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22l5.97-5.97v0.94C19.75,16.66,20.09,17,20.5,17z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_bluetooth.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
new file mode 100644
index 0000000..d2eb2d3
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.53,6.72l-4.75-4.75c-0.21-0.21-0.54-0.28-0.82-0.16C11.68,1.92,11.5,2.2,11.5,2.5v7.69L7.53,6.22 c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L11.19,12l-4.72,4.72c-0.29,0.29-0.29,0.77,0,1.06s0.77,0.29,1.06,0l3.97-3.97v7.69 c0,0.3,0.18,0.58,0.46,0.69c0.09,0.04,0.19,0.06,0.29,0.06c0.2,0,0.39-0.08,0.53-0.22l4.75-4.75c0.29-0.29,0.29-0.77,0-1.06 L13.31,12l4.22-4.22C17.82,7.49,17.82,7.01,17.53,6.72z M15.94,16.75L13,19.69v-5.88L15.94,16.75z M13,10.19V4.31l2.94,2.94 L13,10.19z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_dnd.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_dnd.xml
new file mode 100644
index 0000000..77a84ba
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_dnd.xml
@@ -0,0 +1,29 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.25,11.25h-8.5C7.34,11.25,7,11.59,7,12s0.34,0.75,0.75,0.75h8.5c0.41,0,0.75-0.34,0.75-0.75S16.66,11.25,16.25,11.25z" />
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.49,2,2,6.49,2,12s4.49,10,10,10c0,0,0.01,0,0.01,0c5.5,0,9.98-4.47,9.99-9.98V12C22,6.49,17.51,2,12,2z M20.5,12.02c0,4.68-3.81,8.48-8.49,8.48c0,0-0.01,0-0.01,0c-4.69,0-8.5-3.81-8.5-8.5S7.31,3.5,12,3.5s8.5,3.81,8.5,8.5V12.02z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_flashlight.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_flashlight.xml
similarity index 68%
rename from packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
rename to packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_flashlight.xml
index 3bde46f..9168c20 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_flashlight.xml
@@ -21,11 +21,9 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ android:fillColor="@android:color/white"
+ android:pathData="M17,2H7C6.59,2,6.25,2.34,6.25,2.75v5c0,0.14,0.04,0.27,0.11,0.39l1.89,3.07v10.04C8.25,21.66,8.59,22,9,22h6 c0.41,0,0.75-0.34,0.75-0.75v-9.79l1.89-3.07c0.07-0.12,0.11-0.25,0.11-0.39V2.75C17.75,2.34,17.41,2,17,2z M16.25,7.79 l-1.89,3.07c-0.07,0.12-0.11,0.25-0.11,0.39v9.25h-4.5V11c0-0.14-0.04-0.27-0.11-0.39L7.75,7.54V6.5h8.5V7.79z M16.25,5h-8.5V3.5 h8.5V5z" />
<path
- android:fillColor="#000000"
- android:pathData="M9,22h6a0.76 0.76 ,0,0,0,0.75-0.75V11.46l1.89-3.07A0.77 0.77 ,0,0,0,17.75,8V2.75A0.76 0.76 ,0,0,0,17,2H7a0.76 0.76 ,0,0,0-0.75 0.75 v5a0.77 0.77 ,0,0,0,0.11 0.39 l1.89,3.07v10A0.76 0.76 ,0,0,0,9,22ZM16.25,3.5V5H7.75V3.5Zm-8.5,4v-1h8.5V7.79l-1.89,3.07a0.77 0.77 ,0,0,0-0.11 0.39 V20.5H9.75V11a0.77 0.77 ,0,0,0-0.11-0.39Z" />
- <path
- android:fillColor="#000000"
+ android:fillColor="@android:color/white"
android:pathData="M 12 12.75 C 12.6903559373 12.75 13.25 13.3096440627 13.25 14 C 13.25 14.6903559373 12.6903559373 15.25 12 15.25 C 11.3096440627 15.25 10.75 14.6903559373 10.75 14 C 10.75 13.3096440627 11.3096440627 12.75 12 12.75 Z" />
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_settings_bluetooth.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
new file mode 100644
index 0000000..d2eb2d3
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.53,6.72l-4.75-4.75c-0.21-0.21-0.54-0.28-0.82-0.16C11.68,1.92,11.5,2.2,11.5,2.5v7.69L7.53,6.22 c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L11.19,12l-4.72,4.72c-0.29,0.29-0.29,0.77,0,1.06s0.77,0.29,1.06,0l3.97-3.97v7.69 c0,0.3,0.18,0.58,0.46,0.69c0.09,0.04,0.19,0.06,0.29,0.06c0.2,0,0.39-0.08,0.53-0.22l4.75-4.75c0.29-0.29,0.29-0.77,0-1.06 L13.31,12l4.22-4.22C17.82,7.49,17.82,7.01,17.53,6.72z M15.94,16.75L13,19.69v-5.88L15.94,16.75z M13,10.19V4.31l2.94,2.94 L13,10.19z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml
new file mode 100644
index 0000000..e884edb
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M2.52,16.17c0.32,0.23,0.74,0.31,1.11,0.19l5.87-1.84v3.87L8,19.52c-0.31,0.24-0.5,0.61-0.5,1v0.75 c0,0.69,0.56,1.25,1.25,1.25h6.5c0.69,0,1.25-0.56,1.25-1.25v-0.75c0-0.39-0.19-0.76-0.5-1l-1.5-1.12v-3.87l5.88,1.84 c0.38,0.12,0.79,0.05,1.11-0.19c0.32-0.23,0.51-0.61,0.51-1.01l0-1.84c0-0.63-0.34-1.21-0.89-1.52L14.5,8.06V4 c0-1.38-1.12-2.5-2.5-2.5S9.5,2.62,9.5,4v4.07L2.89,11.8C2.35,12.11,2,12.7,2,13.33l0,1.83C2.01,15.56,2.2,15.94,2.52,16.17z M3.63,13.11L11,8.94V4c0-0.55,0.45-1,1-1s1,0.45,1,1v4.94l7.37,4.17c0.08,0.04,0.13,0.13,0.13,0.22l0,1.5L13,12.48v6.66l2,1.5 v0.38H9v-0.38l2-1.5v-6.66l-7.5,2.34l0-1.49C3.5,13.24,3.55,13.15,3.63,13.11z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dnd.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dnd.xml
deleted file mode 100644
index a9a32ee..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dnd.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M7.25,12.75h9.5a0.75 0.75 ,0,0,0,0-1.5H7.25a0.75 0.75 ,0,0,0,0,1.5Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12,22h0A10,10,0,0,0,22,12v0A10,10,0,1,0,12,22ZM12,3.5A8.51,8.51,0,0,1,20.5,12h0.75l-0.75,0A8.49,8.49,0,0,1,12,20.5h0a8.5,8.5,0,0,1,0-17Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
deleted file mode 100644
index 7897fa3a..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M3,21H21a2,2,0,0,0,2-2V6a2,2,0,0,0-2-2H3A2,2,0,0,0,1,6V19A2,2,0,0,0,3,21ZM2.5,6A0.51 0.51 ,0,0,1,3,5.5H21a0.51 0.51 ,0,0,1,0.5 0.5 V19a0.51 0.51 ,0,0,1-0.5 0.5 H3a0.51 0.51 ,0,0,1-0.5-0.5Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 9.5 8 L 10.5 8 Q 11 8 11 8.5 L 11 9.5 Q 11 10 10.5 10 L 9.5 10 Q 9 10 9 9.5 L 9 8.5 Q 9 8 9.5 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 5.5 8 L 6.5 8 Q 7 8 7 8.5 L 7 9.5 Q 7 10 6.5 10 L 5.5 10 Q 5 10 5 9.5 L 5 8.5 Q 5 8 5.5 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M8.75,17.5h6.5a0.75 0.75 ,0,0,0,0-1.5H8.75a0.75 0.75 ,0,0,0,0,1.5Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 13.5 8 L 14.5 8 Q 15 8 15 8.5 L 15 9.5 Q 15 10 14.5 10 L 13.5 10 Q 13 10 13 9.5 L 13 8.5 Q 13 8 13.5 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 9.5 12 L 10.5 12 Q 11 12 11 12.5 L 11 13.5 Q 11 14 10.5 14 L 9.5 14 Q 9 14 9 13.5 L 9 12.5 Q 9 12 9.5 12 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 5.5 12 L 6.5 12 Q 7 12 7 12.5 L 7 13.5 Q 7 14 6.5 14 L 5.5 14 Q 5 14 5 13.5 L 5 12.5 Q 5 12 5.5 12 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 13.5 12 L 14.5 12 Q 15 12 15 12.5 L 15 13.5 Q 15 14 14.5 14 L 13.5 14 Q 13 14 13 13.5 L 13 12.5 Q 13 12 13.5 12 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 17.5 8 L 18.5 8 Q 19 8 19 8.5 L 19 9.5 Q 19 10 18.5 10 L 17.5 10 Q 17 10 17 9.5 L 17 8.5 Q 17 8 17.5 8 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M 17.5 12 L 18.5 12 Q 19 12 19 12.5 L 19 13.5 Q 19 14 18.5 14 L 17.5 14 Q 17 14 17 13.5 L 17 12.5 Q 17 12 17.5 12 Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
deleted file mode 100644
index fe7ecfd..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M3,6.81a0.75 0.75 ,0,0,0-0.75 0.75 v2.83a0.74 0.74 ,0,0,0,0.75 0.75 H5.8a0.75 0.75 ,0,1,0,0-1.5h-1l5.6-5.59,7.07,7.06a0.75 0.75 ,0,0,0,1.06-1.06l-7.6-7.6a0.75 0.75 ,0,0,0-1.06,0L3.72,8.62V7.56A0.76 0.76 ,0,0,0,3,6.81Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M21,12.85H18.21a0.75 0.75 ,0,0,0,0,1.5h1L13.59,20,6.52,12.89a0.75 0.75 ,0,0,0-1.06,0,0.74 0.74 ,0,0,0,0,1.06l7.6,7.6a0.75 0.75 ,0,0,0,1.06,0l6.17-6.17v1.06a0.75 0.75 ,0,1,0,1.5,0V13.6A0.76 0.76 ,0,0,0,21,12.85Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
deleted file mode 100644
index 9bf1274..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12.75,2.25V0.75a0.75 0.75 ,0,0,0-1.5,0v1.5a0.75 0.75 ,0,0,0,1.5,0Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M4.57,5.64a0.79 0.79 ,0,0,0,1.07,0,0.77 0.77 ,0,0,0,0-1.07L4.58,3.51A0.76 0.76 ,0,0,0,3.51,4.58Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M0.75,12.75h1.5a0.75 0.75 ,0,0,0,0-1.5H0.75a0.75 0.75 ,0,0,0,0,1.5Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M3.51,20.49a0.76 0.76 ,0,0,0,1.07,0l1.06-1.06a0.76 0.76 ,0,1,0-1.07-1.07L3.51,19.42A0.77 0.77 ,0,0,0,3.51,20.49Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M11.25,21.75v1.5a0.75 0.75 ,0,0,0,1.5,0v-1.5a0.75 0.75 ,0,0,0-1.5,0Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M20,20.71a0.79 0.79 ,0,0,0,0.53-0.22 0.77 0.77,0,0,0,0-1.07l-1.06-1.06a0.76 0.76 ,0,0,0-1.07,1.07l1.06,1.06A0.79 0.79 ,0,0,0,20,20.71Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M23.25,11.25h-1.5a0.75 0.75 ,0,0,0,0,1.5h1.5a0.75 0.75 ,0,0,0,0-1.5Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M19.42,3.51,18.36,4.57a0.77 0.77 ,0,0,0,0,1.07 0.79 0.79,0,0,0,1.07,0l1.06-1.06a0.76 0.76 ,0,0,0-1.07-1.07Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M14.85,17H17L13.11,7H10.87L7,17H9.15L10,14.61h4Zm-4.22-4.12,1.31-3.71h0.11l1.29,3.71Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_cast_on.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
deleted file mode 100644
index 34ca21a..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M22,18V5.5A1.5,1.5,0,0,0,20.5,4h-17A1.5,1.5,0,0,0,2,5.53V8.46a0.75 0.75 ,0,0,0,1.5,0v-3l17,0V18H13.15a0.75 0.75 ,0,1,0,0,1.5h7.38A1.5,1.5,0,0,0,22,18Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M3.25,19.5a1.25,1.25,0,0,0,0-2.5h0a1.25,1.25,0,0,0,0,2.5Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M2,11.25a0.76 0.76 ,0,0,0,0.75 0.75 A6.75,6.75,0,0,1,9.5,18.75a0.75 0.75 ,0,0,0,1.5,0A8.25,8.25,0,0,0,2.75,10.5 0.76 0.76,0,0,0,2,11.25Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M2.75,15.25a3.5,3.5,0,0,1,3.5,3.5 0.75 0.75,0,0,0,1.5,0,5,5,0,0,0-5-5,0.75 0.75 ,0,0,0,0,1.5Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M13.25,15a0.75 0.75 ,0,0,0,0,1.5h5a0.76 0.76 ,0,0,0,0.75-0.75v-8A0.76 0.76 ,0,0,0,18.25,7H5.75A0.76 0.76 ,0,0,0,5,7.75V8.5a0.75 0.75 ,0,0,0,1.5,0h11V15Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_settings_16dp.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_settings_16dp.xml
deleted file mode 100644
index 4237323..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_settings_16dp.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="16dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M2.2,15.53,4,18.7a1.46,1.46,0,0,0,1.28 0.75 ,1.61,1.61,0,0,0,0.53-0.1l1.8-0.72a9,9,0,0,0,0.79 0.46 L8.7,21a1.45,1.45,0,0,0,1.45,1.27h3.7A1.47,1.47,0,0,0,15.31,21l0.27-1.91c0.26-0.14 0.52 -0.29 0.78 -0.46l1.8 0.72 a1.47,1.47,0,0,0,0.54 0.1 A1.43,1.43,0,0,0,20,18.75l1.86-3.22a1.47,1.47,0,0,0-0.37-1.86l-1.52-1.19c0-0.15,0-0.3,0-0.46s0-0.31,0-0.46l1.52-1.19a1.47,1.47,0,0,0,0.36-1.88L20,5.31a1.46,1.46,0,0,0-1.29-0.75,1.71,1.71,0,0,0-0.53 0.1 l-1.8 0.72 a9,9,0,0,0-0.79-0.46L15.29,3a1.45,1.45,0,0,0-1.45-1.27h-3.7A1.46,1.46,0,0,0,8.7,3L8.43,4.92c-0.26 0.14 -0.52 0.29 -0.78 0.46 L5.84,4.65a1.47,1.47,0,0,0-0.54-0.1,1.42,1.42,0,0,0-1.25 0.73 L2.2,8.47a1.44,1.44,0,0,0,0.37,1.88l1.52,1.19c0,0.15,0,0.31,0,0.46s0,0.31,0,0.46L2.56,13.65A1.48,1.48,0,0,0,2.2,15.53ZM5,13.64l0.63-0.49,0-0.79c0-0.12,0-0.23,0-0.36s0-0.24,0-0.36l0-0.79L5,10.36,3.52,9.19,5.33,6.06l1.76 0.71 0.73 0.29 0.65-0.42a6.59,6.59,0,0,1,0.67-0.4l0.67-0.36 0.11 -0.75 0.26 -1.87h3.63l0.27,1.87 0.1 0.77 0.69 0.35a6,6,0,0,1,0.66 0.39 l0.65 0.42 0.73-0.29,1.76-0.71L20.5,9.21,19,10.38l-0.63 0.49 0.05 0.79 c0,0.12,0,0.23,0,0.36s0,0.24,0,0.36l-0.05 0.79 0.63 0.49 ,1.48,1.17L18.68,18l-1.76-0.7L16.19,17l-0.65 0.42 a6.59,6.59,0,0,1-0.67 0.4 l-0.67 0.36 -0.11 0.75 -0.26,1.84H10.18l-0.27-1.87-0.1-0.77-0.69-0.35a6,6,0,0,1-0.66-0.39L7.81,17l-0.73 0.29 L5.33,18,3.52,14.8Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M12,16a4,4,0,1,0-4-4A4,4,0,0,0,12,16Zm0-6.5A2.5,2.5,0,1,1,9.5,12,2.5,2.5,0,0,1,12,9.5Z" />
-</vector>
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_airplane.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_airplane.xml
deleted file mode 100644
index 2d36a39..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_airplane.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-/**
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#000000"
- android:pathData="M2.52,16.17a1.25,1.25,0,0,0,1.11 0.19 L9.5,14.52v3.87L8,19.52a1.26,1.26,0,0,0-0.5,1v0.75a1.25,1.25,0,0,0,1.25,1.25h6.5a1.25,1.25,0,0,0,1.25-1.25v-0.75a1.26,1.26,0,0,0-0.5-1l-1.5-1.13V14.52l5.88,1.84a1.23,1.23,0,0,0,1.11-0.19,1.25,1.25,0,0,0,0.51-1V13.33a1.74,1.74,0,0,0-0.89-1.52L14.5,8.06V3.75a2.5,2.5,0,0,0-5,0V8.06L2.89,11.8A1.78,1.78,0,0,0,2,13.33v1.83A1.25,1.25,0,0,0,2.52,16.17Zm1.11-3.06L11,8.94V3.75a1,1,0,0,1,2,0V8.94l7.37,4.17a0.26 0.26 ,0,0,1,0.13 0.22 v1.49L13,12.48v6.66l2,1.5V21H9v-0.38l2-1.5V12.48L3.51,14.82V13.33A0.25 0.25 ,0,0,1,3.63,13.11Z" />
-</vector>
\ No newline at end of file
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index f52b94f..ce39a70 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7158,6 +7158,10 @@
// OPEN: Settings > System > Aware > Info dialog
DIALOG_AWARE_STATUS = 1701;
+
+ // Open: Settings > app > bubble settings > confirmation dialog
+ DIALOG_APP_BUBBLE_SETTINGS = 1702;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 1ce0c52..af77df6 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1752,6 +1752,9 @@
// Firmware generated an alert
TYPE_FIRMWARE_ALERT = 4;
+
+ // IP Manager lost reachability to network neighbors
+ TYPE_IP_REACHABILITY_LOST = 5;
}
// What event triggered WifiIsUnusableEvent.
@@ -2012,6 +2015,10 @@
// Whether the primary registered cell of current entry is same as that of previous entry
optional bool is_same_registered_cell = 33;
+
+ // The device mobility state
+ optional DeviceMobilityStatePnoScanStats.DeviceMobilityState
+ device_mobility_state = 34;
}
message WifiUsabilityStats {
@@ -2041,6 +2048,9 @@
// Firmware generated an alert
TYPE_FIRMWARE_ALERT = 4;
+
+ // IP Manager lost reachability to network neighbors
+ TYPE_IP_REACHABILITY_LOST = 5;
}
// The current wifi usability state
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 7020e7e..fdc3567 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -42,6 +42,7 @@
import android.database.ContentObserver;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
@@ -61,6 +62,7 @@
import android.util.LocalLog;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -72,6 +74,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AbstractRemoteService;
+import com.android.internal.infra.GlobalWhitelistState;
+import com.android.internal.infra.WhitelistHelper;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
@@ -146,6 +150,7 @@
private final LocalLog mWtfHistory = new LocalLog(50);
private final AutofillCompatState mAutofillCompatState = new AutofillCompatState();
+
private final LocalService mLocalService = new LocalService();
private final ActivityManagerInternal mAm;
@@ -178,6 +183,8 @@
@GuardedBy("mLock")
int mAugmentedServiceRequestTimeoutMs;
+ final AugmentedAutofillState mAugmentedAutofillState = new AugmentedAutofillState();
+
public AutofillManagerService(Context context) {
super(context,
new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE),
@@ -187,7 +194,7 @@
DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
ActivityThread.currentApplication().getMainExecutor(),
- (namespace, key, value) -> onDeviceConfigChange(key, value));
+ (namespace, key, value) -> onDeviceConfigChange(key));
setLogLevelFromSettings();
setMaxPartitionsFromSettings();
@@ -201,15 +208,20 @@
mAugmentedAutofillResolver = new FrameworkResourcesServiceNameResolver(getContext(),
com.android.internal.R.string.config_defaultAugmentedAutofillService);
mAugmentedAutofillResolver.setOnTemporaryServiceNameChangedCallback(
- (u, s) -> getServiceForUserLocked(u).updateRemoteAugmentedAutofillService());
+ (u, s, t) -> onAugmentedServiceNameChanged(u, s, t));
if (mSupportedSmartSuggestionModes != AutofillManager.FLAG_SMART_SUGGESTION_OFF) {
- // Must eager load the services so they bind to the augmented autofill service
final UserManager um = getContext().getSystemService(UserManager.class);
final List<UserInfo> users = um.getUsers();
for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id;
+ // Must eager load the services so they bind to the augmented autofill service
getServiceForUserLocked(userId);
+
+ // And also set the global state
+ mAugmentedAutofillState.setServiceInfo(userId,
+ mAugmentedAutofillResolver.getServiceName(userId),
+ mAugmentedAutofillResolver.isTemporary(userId));
}
}
}
@@ -258,7 +270,7 @@
}
}
- private void onDeviceConfigChange(@NonNull String key, @Nullable String value) {
+ private void onDeviceConfigChange(@NonNull String key) {
switch (key) {
case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
@@ -270,6 +282,14 @@
}
}
+ private void onAugmentedServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName,
+ boolean isTemporary) {
+ mAugmentedAutofillState.setServiceInfo(userId, serviceName, isTemporary);
+ synchronized (mLock) {
+ getServiceForUserLocked(userId).updateRemoteAugmentedAutofillService();
+ }
+ }
+
@Override // from AbstractMasterSystemService
protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
boolean disabled) {
@@ -783,15 +803,7 @@
final boolean compatModeEnabled = mAutofillCompatState.isCompatibilityModeRequested(
packageName, versionCode, userId);
final AutofillOptions options = new AutofillOptions(loggingLevel, compatModeEnabled);
-
- synchronized (mLock) {
- final AutofillManagerServiceImpl service =
- getServiceForUserLocked(UserHandle.getCallingUserId());
- if (service != null) {
- service.setAugmentedAutofillWhitelistLocked(options, packageName);
- }
- }
-
+ mAugmentedAutofillState.injectAugmentedAutofillInfo(options, userId, packageName);
return options;
}
}
@@ -934,6 +946,89 @@
}
}
+ /**
+ * Augmented autofill metadata associated with all services.
+ *
+ * <p>This object is defined here instead of on each {@link AutofillManagerServiceImpl} because
+ * it cannot hold a lock on the main lock when
+ * {@link AugmentedAutofillState#injectAugmentedAutofillInfo(AutofillOptions, int, String)}
+ * is called by external services.
+ */
+ static final class AugmentedAutofillState extends GlobalWhitelistState {
+
+ @GuardedBy("mGlobalWhitelistStateLock")
+ private final SparseArray<String> mServicePackages = new SparseArray<>();
+ @GuardedBy("mGlobalWhitelistStateLock")
+ private final SparseBooleanArray mTemporaryServices = new SparseBooleanArray();
+
+ private void setServiceInfo(@UserIdInt int userId, @Nullable String serviceName,
+ boolean isTemporary) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (isTemporary) {
+ mTemporaryServices.put(userId, true);
+ } else {
+ mTemporaryServices.delete(userId);
+ }
+ if (serviceName != null) {
+ final ComponentName componentName =
+ ComponentName.unflattenFromString(serviceName);
+ if (componentName == null) {
+ Slog.w(TAG, "setServiceInfo(): invalid name: " + serviceName);
+ mServicePackages.remove(userId);
+ } else {
+ mServicePackages.put(userId, componentName.getPackageName());
+ }
+ } else {
+ mServicePackages.remove(userId);
+ }
+ }
+ }
+
+ public void injectAugmentedAutofillInfo(@NonNull AutofillOptions options,
+ @UserIdInt int userId, @NonNull String packageName) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (mWhitelisterHelpers == null) return;
+ final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+ if (helper != null) {
+ options.augmentedAutofillEnabled = helper.isWhitelisted(packageName);
+ options.whitelistedActivitiesForAugmentedAutofill = helper
+ .getWhitelistedComponents(packageName);
+ }
+ }
+ }
+
+ @Override
+ public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (!super.isWhitelisted(userId, componentName)) return false;
+
+ if (Build.IS_USER && mTemporaryServices.get(userId)) {
+ final String packageName = componentName.getPackageName();
+ if (!packageName.equals(mServicePackages.get(userId))) {
+ Slog.w(TAG, "Ignoring package " + packageName + " for augmented autofill "
+ + "while using temporary service " + mServicePackages.get(userId));
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ super.dump(prefix, pw);
+
+ synchronized (mGlobalWhitelistStateLock) {
+ if (mServicePackages.size() > 0) {
+ pw.print(prefix); pw.print("Service packages: "); pw.println(mServicePackages);
+ }
+ if (mTemporaryServices.size() > 0) {
+ pw.print(prefix); pw.print("Temp services: "); pw.println(mTemporaryServices);
+ }
+ }
+ }
+ }
+
final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
@Override
public void addClient(IAutoFillManagerClient client, ComponentName componentName,
@@ -1370,6 +1465,8 @@
pw.println(); pw.println("WTF history:"); pw.println();
mWtfHistory.reverseDump(fd, pw, args);
}
+ pw.println("Augmented Autofill State: ");
+ mAugmentedAutofillState.dump(prefix, pw);
}
} finally {
sDebug = realDebug;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index fe540bf..4bd6fbd 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -31,7 +31,6 @@
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
-import android.content.AutofillOptions;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -40,7 +39,6 @@
import android.metrics.LogMaker;
import android.os.AsyncTask;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -76,7 +74,6 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.WhitelistHelper;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.LocalServices;
@@ -170,12 +167,6 @@
@Nullable
private ServiceInfo mRemoteAugmentedAutofillServiceInfo;
- /**
- * List of packages/activities that are whitelisted to be trigger augmented autofill.
- */
- @GuardedBy("mLock")
- private final WhitelistHelper mAugmentedWhitelistHelper = new WhitelistHelper();
-
AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
AutofillCompatState autofillCompatState,
@@ -951,8 +942,6 @@
pw.println(mRemoteAugmentedAutofillServiceInfo);
}
- mAugmentedWhitelistHelper.dump(prefix, "Augmented autofill whitelist", pw);
-
pw.print(prefix); pw.print("Field classification enabled: ");
pw.println(isFieldClassificationEnabledLocked());
pw.print(prefix); pw.print("Compat pkgs: ");
@@ -1234,27 +1223,7 @@
@GuardedBy("mLock")
boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) {
- if (Build.IS_USER && mMaster.mAugmentedAutofillResolver.isTemporary(mUserId)) {
- final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
- final ComponentName component = ComponentName.unflattenFromString(serviceName);
- final String servicePackage = component == null ? null : component.getPackageName();
- final String packageName = componentName.getPackageName();
- if (!packageName.equals(servicePackage)) {
- Slog.w(TAG, "Ignoring package " + packageName + " for augmented autofill while "
- + "using temporary service " + servicePackage);
- return false;
- }
- }
-
- return mAugmentedWhitelistHelper.isWhitelisted(componentName);
- }
-
- @GuardedBy("mLock")
- void setAugmentedAutofillWhitelistLocked(@NonNull AutofillOptions options,
- @NonNull String packageName) {
- options.augmentedAutofillEnabled = mAugmentedWhitelistHelper.isWhitelisted(packageName);
- options.whitelistedActivitiesForAugmentedAutofill = mAugmentedWhitelistHelper
- .getWhitelistedComponents(packageName);
+ return mMaster.mAugmentedAutofillState.isWhitelisted(mUserId, componentName);
}
/**
@@ -1268,7 +1237,7 @@
if (mMaster.verbose) {
Slog.v(TAG, "whitelisting packages: " + packages + "and activities: " + components);
}
- mAugmentedWhitelistHelper.setWhitelist(packages, components);
+ mMaster.mAugmentedAutofillState.setWhitelist(mUserId, packages, components);
}
}
@@ -1280,7 +1249,7 @@
if (mMaster.verbose) {
Slog.v(TAG, "resetting augmented autofill whitelist");
}
- whitelistForAugmentedAutofillPackages(null, null);
+ mMaster.mAugmentedAutofillState.resetWhitelist(mUserId);
}
private void sendStateToClients(boolean resetClient) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c62794d..0402b8f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2540,13 +2540,14 @@
boolean saveOnFinish = true;
final SaveInfo saveInfo = response.getSaveInfo();
final AutofillId saveTriggerId;
+ final int flags;
if (saveInfo != null) {
saveTriggerId = saveInfo.getTriggerId();
if (saveTriggerId != null) {
writeLog(MetricsEvent.AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION);
}
- mSaveOnAllViewsInvisible =
- (saveInfo.getFlags() & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
+ flags = saveInfo.getFlags();
+ mSaveOnAllViewsInvisible = (flags & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
// We only need to track views if we want to save once they become invisible.
if (mSaveOnAllViewsInvisible) {
@@ -2561,11 +2562,12 @@
Collections.addAll(trackedViews, saveInfo.getOptionalIds());
}
}
- if ((saveInfo.getFlags() & SaveInfo.FLAG_DONT_SAVE_ON_FINISH) != 0) {
+ if ((flags & SaveInfo.FLAG_DONT_SAVE_ON_FINISH) != 0) {
saveOnFinish = false;
}
} else {
+ flags = 0;
saveTriggerId = null;
}
@@ -2592,7 +2594,8 @@
try {
if (sVerbose) {
Slog.v(TAG, "updateTrackedIdsLocked(): " + trackedViews + " => " + fillableIds
- + " triggerId: " + saveTriggerId + " saveOnFinish:" + saveOnFinish);
+ + " triggerId: " + saveTriggerId + " saveOnFinish:" + saveOnFinish
+ + " flags: " + flags + " hasSaveInfo: " + (saveInfo != null));
}
mClient.setTrackedViews(id, toArray(trackedViews), mSaveOnAllViewsInvisible,
saveOnFinish, toArray(fillableIds), saveTriggerId);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 3865b27..a7404bc 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -72,7 +72,9 @@
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -84,6 +86,7 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -519,6 +522,11 @@
if (size(old) == size(associations)) return;
Set<Association> finalAssociations = associations;
+ Set<String> companionAppPackages = new HashSet<>();
+ for (Association association : finalAssociations) {
+ companionAppPackages.add(association.companionAppPackage);
+ }
+
file.write((out) -> {
XmlSerializer xml = Xml.newSerializer();
try {
@@ -542,6 +550,9 @@
}
});
+ ActivityTaskManagerInternal atmInternal = LocalServices.getService(
+ ActivityTaskManagerInternal.class);
+ atmInternal.setCompanionAppPackages(userId, companionAppPackages);
}
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index b2760e0..9b02c4e 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
+import static android.view.contentcapture.ContentCaptureHelper.toList;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
@@ -40,6 +41,7 @@
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -50,9 +52,12 @@
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.contentcapture.ActivityEvent.ActivityEventType;
+import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.view.contentcapture.ContentCaptureCondition;
import android.view.contentcapture.ContentCaptureHelper;
import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.IContentCaptureManager;
@@ -60,6 +65,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AbstractRemoteService;
+import com.android.internal.infra.GlobalWhitelistState;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
@@ -117,10 +123,13 @@
@GuardedBy("mLock") int mDevCfgLogHistorySize;
@GuardedBy("mLock") int mDevCfgIdleUnbindTimeoutMs;
+ final GlobalContentCaptureOptions mGlobalContentCaptureOptions =
+ new GlobalContentCaptureOptions();
+
public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
com.android.internal.R.string.config_defaultContentCaptureService),
- UserManager.DISALLOW_CONTENT_CAPTURE, /* refreshServiceOnPackageUpdate=*/ false);
+ UserManager.DISALLOW_CONTENT_CAPTURE, /* refreshServiceOnPackageUpdate= */ false);
DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
ActivityThread.currentApplication().getMainExecutor(),
(namespace, key, value) -> onDeviceConfigChange(key, value));
@@ -136,12 +145,12 @@
mRequestsHistory = null;
}
- // Sets which services are disabled by settings
final UserManager um = getContext().getSystemService(UserManager.class);
final List<UserInfo> users = um.getUsers();
for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id;
final boolean disabled = !isEnabledBySettings(userId);
+ // Sets which services are disabled by settings
if (disabled) {
Slog.i(mTag, "user " + userId + " disabled by settings");
if (mDisabledBySettings == null) {
@@ -149,6 +158,10 @@
}
mDisabledBySettings.put(userId, true);
}
+ // Sets the global options for the service.
+ mGlobalContentCaptureOptions.setServiceInfo(userId,
+ mServiceNameResolver.getServiceName(userId),
+ mServiceNameResolver.isTemporary(userId));
}
}
@@ -188,6 +201,14 @@
}
@Override // from AbstractMasterSystemService
+ protected void onServiceNameChanged(@UserIdInt int userId, @NonNull String serviceName,
+ boolean isTemporary) {
+ mGlobalContentCaptureOptions.setServiceInfo(userId, serviceName, isTemporary);
+
+ super.onServiceNameChanged(userId, serviceName, isTemporary);
+ }
+
+ @Override // from AbstractMasterSystemService
protected void enforceCallingPermissionForManagement() {
getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, mTag);
}
@@ -429,23 +450,16 @@
}
@GuardedBy("mLock")
- private boolean assertCalledByServiceLocked(@NonNull String methodName, @UserIdInt int userId,
- int callingUid, @NonNull IResultReceiver result) {
- final boolean isService = isCalledByServiceLocked(methodName, userId, callingUid);
- if (isService) return true;
-
- try {
- result.send(RESULT_CODE_SECURITY_EXCEPTION, /* resultData= */ null);
- } catch (RemoteException e) {
- Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e);
+ private void assertCalledByServiceLocked(@NonNull String methodName) {
+ if (!isCalledByServiceLocked(methodName)) {
+ throw new SecurityException("caller is not user's ContentCapture service");
}
- return false;
}
@GuardedBy("mLock")
- private boolean isCalledByServiceLocked(@NonNull String methodName, @UserIdInt int userId,
- int callingUid) {
-
+ private boolean isCalledByServiceLocked(@NonNull String methodName) {
+ final int userId = UserHandle.getCallingUserId();
+ final int callingUid = Binder.getCallingUid();
final String serviceName = mServiceNameResolver.getServiceName(userId);
if (serviceName == null) {
Slog.e(mTag, methodName + ": called by UID " + callingUid
@@ -453,7 +467,7 @@
return false;
}
- final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+ final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
if (serviceComponent == null) {
Slog.w(mTag, methodName + ": invalid service name: " + serviceName);
return false;
@@ -478,6 +492,27 @@
return true;
}
+ /**
+ * Executes the given {@code runnable} and if it throws a {@link SecurityException},
+ * send it back to the receiver.
+ *
+ * @return whether the exception was thrown or not.
+ */
+ private boolean throwsSecurityException(@NonNull IResultReceiver result,
+ @NonNull Runnable runable) {
+ try {
+ runable.run();
+ return false;
+ } catch (SecurityException e) {
+ try {
+ result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage()));
+ } catch (RemoteException e2) {
+ Slog.w(mTag, "Unable to send security exception (" + e + "): ", e2);
+ }
+ }
+ return true;
+ }
+
@Override // from AbstractMasterSystemService
protected void dumpLocked(String prefix, PrintWriter pw) {
super.dumpLocked(prefix, pw);
@@ -496,13 +531,15 @@
pw.print(prefix2); pw.print("logHistorySize: "); pw.println(mDevCfgLogHistorySize);
pw.print(prefix2); pw.print("idleUnbindTimeoutMs: ");
pw.println(mDevCfgIdleUnbindTimeoutMs);
+ pw.print(prefix); pw.println("Global Options:");
+ mGlobalContentCaptureOptions.dump(prefix2, pw);
}
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
@Override
public void startSession(@NonNull IBinder activityToken,
- @NonNull ComponentName componentName, @NonNull String sessionId, int flags,
+ @NonNull ComponentName componentName, int sessionId, int flags,
@NonNull IResultReceiver result) {
Preconditions.checkNotNull(activityToken);
Preconditions.checkNotNull(sessionId);
@@ -519,7 +556,7 @@
}
@Override
- public void finishSession(@NonNull String sessionId) {
+ public void finishSession(int sessionId) {
Preconditions.checkNotNull(sessionId);
final int userId = UserHandle.getCallingUserId();
@@ -547,6 +584,8 @@
@Override
public void removeUserData(@NonNull UserDataRemovalRequest request) {
Preconditions.checkNotNull(request);
+ assertCalledByPackageOwner(request.getPackageName());
+
final int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
final ContentCapturePerUserService service = getServiceForUserLocked(userId);
@@ -556,13 +595,14 @@
@Override
public void isContentCaptureFeatureEnabled(@NonNull IResultReceiver result) {
- final int userId = UserHandle.getCallingUserId();
boolean enabled;
synchronized (mLock) {
- final boolean isService = assertCalledByServiceLocked(
- "isContentCaptureFeatureEnabled()", userId, Binder.getCallingUid(), result);
- if (!isService) return;
+ if (throwsSecurityException(result,
+ () -> assertCalledByServiceLocked("isContentCaptureFeatureEnabled()"))) {
+ return;
+ }
+ final int userId = UserHandle.getCallingUserId();
enabled = !mDisabledByDeviceConfig && !isDisabledBySettingsLocked(userId);
}
try {
@@ -574,15 +614,8 @@
@Override
public void getServiceSettingsActivity(@NonNull IResultReceiver result) {
- try {
- enforceCallingPermissionForManagement();
- } catch (SecurityException e) {
- try {
- result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage()));
- } catch (RemoteException e2) {
- Slog.w(mTag, "Unable to send getServiceSettingsIntent() exception: " + e2);
- return;
- }
+ if (throwsSecurityException(result, () -> enforceCallingPermissionForManagement())) {
+ return;
}
final int userId = UserHandle.getCallingUserId();
@@ -600,13 +633,34 @@
}
@Override
+ public void getContentCaptureConditions(@NonNull String packageName,
+ @NonNull IResultReceiver result) {
+ if (throwsSecurityException(result, () -> assertCalledByPackageOwner(packageName))) {
+ return;
+ }
+
+ final int userId = UserHandle.getCallingUserId();
+ final ArrayList<ContentCaptureCondition> conditions;
+ synchronized (mLock) {
+ final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+ conditions = service == null ? null
+ : toList(service.getContentCaptureConditionsLocked(packageName));
+ }
+ try {
+ result.send(RESULT_CODE_OK, bundleFor(conditions));
+ } catch (RemoteException e) {
+ Slog.w(mTag, "Unable to send getServiceComponentName(): " + e);
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return;
boolean showHistory = true;
if (args != null) {
for (String arg : args) {
- switch(arg) {
+ switch (arg) {
case "--no-history":
showHistory = false;
break;
@@ -670,13 +724,7 @@
@Override
public ContentCaptureOptions getOptionsForPackage(int userId, @NonNull String packageName) {
- synchronized (mLock) {
- final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
- if (service != null) {
- return service.getOptionsForPackageLocked(packageName);
- }
- }
- return null;
+ return mGlobalContentCaptureOptions.getOptions(userId, packageName);
}
@Override
@@ -690,4 +738,92 @@
}
}
}
+
+ /**
+ * Content capture options associated with all services.
+ *
+ * <p>This object is defined here instead of on each {@link ContentCapturePerUserService}
+ * because it cannot hold a lock on the main lock when
+ * {@link GlobalContentCaptureOptions#getOptions(int, String)} is called by external services.
+ */
+ final class GlobalContentCaptureOptions extends GlobalWhitelistState {
+
+ @GuardedBy("mGlobalWhitelistStateLock")
+ private final SparseArray<String> mServicePackages = new SparseArray<>();
+ @GuardedBy("mGlobalWhitelistStateLock")
+ private final SparseBooleanArray mTemporaryServices = new SparseBooleanArray();
+
+ private void setServiceInfo(@UserIdInt int userId, @Nullable String serviceName,
+ boolean isTemporary) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (isTemporary) {
+ mTemporaryServices.put(userId, true);
+ } else {
+ mTemporaryServices.delete(userId);
+ }
+ if (serviceName != null) {
+ final ComponentName componentName =
+ ComponentName.unflattenFromString(serviceName);
+ if (componentName == null) {
+ Slog.w(mTag, "setServiceInfo(): invalid name: " + serviceName);
+ mServicePackages.remove(userId);
+ } else {
+ mServicePackages.put(userId, componentName.getPackageName());
+ }
+ } else {
+ mServicePackages.remove(userId);
+ }
+ }
+ }
+
+ @Nullable
+ @GuardedBy("mGlobalWhitelistStateLock")
+ public ContentCaptureOptions getOptions(@UserIdInt int userId,
+ @NonNull String packageName) {
+ synchronized (mGlobalWhitelistStateLock) {
+ if (!isWhitelisted(userId, packageName)) {
+ if (packageName.equals(mServicePackages.get(userId))) {
+ if (verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
+ return new ContentCaptureOptions(mDevCfgLoggingLevel);
+ }
+ if (verbose) {
+ Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
+ }
+ return null;
+ }
+
+ final ArraySet<ComponentName> whitelistedComponents =
+ getWhitelistedComponents(userId, packageName);
+ if (Build.IS_USER && mServiceNameResolver.isTemporary(userId)) {
+ if (!packageName.equals(mServicePackages.get(userId))) {
+ Slog.w(mTag, "Ignoring package " + packageName
+ + " while using temporary service " + mServicePackages.get(userId));
+ return null;
+ }
+ }
+ final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel,
+ mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs,
+ mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize,
+ whitelistedComponents);
+ if (verbose) {
+ Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
+ }
+ return options;
+ }
+ }
+
+ @Override
+ public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ super.dump(prefix, pw);
+
+ synchronized (mGlobalWhitelistStateLock) {
+ if (mServicePackages.size() > 0) {
+ pw.print(prefix); pw.print("Service packages: "); pw.println(mServicePackages);
+ }
+ if (mTemporaryServices.size() > 0) {
+ pw.print(prefix); pw.print("Temp services: "); pw.println(mTemporaryServices);
+ }
+ }
+ }
+ }
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index f0c6f7e..5649526 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -17,6 +17,7 @@
package com.android.server.contentcapture;
import static android.service.contentcapture.ContentCaptureService.setClientState;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
import static android.view.contentcapture.ContentCaptureSession.STATE_DUPLICATED_ID;
import static android.view.contentcapture.ContentCaptureSession.STATE_INTERNAL_ERROR;
@@ -54,6 +55,8 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
+import android.util.SparseArray;
+import android.view.contentcapture.ContentCaptureCondition;
import android.view.contentcapture.UserDataRemovalRequest;
import com.android.internal.annotations.GuardedBy;
@@ -78,8 +81,7 @@
private static final String TAG = ContentCapturePerUserService.class.getSimpleName();
@GuardedBy("mLock")
- private final ArrayMap<String, ContentCaptureServerSession> mSessions =
- new ArrayMap<>();
+ private final SparseArray<ContentCaptureServerSession> mSessions = new SparseArray<>();
/**
* Reference to the remote service.
@@ -101,6 +103,13 @@
private final WhitelistHelper mWhitelistHelper = new WhitelistHelper();
/**
+ * List of conditions keyed by package.
+ */
+ @GuardedBy("mLock")
+ private final ArrayMap<String, ArraySet<ContentCaptureCondition>> mConditionsByPkg =
+ new ArrayMap<>();
+
+ /**
* When {@code true}, remote service died but service state is kept so it's restored after
* the system re-binds to it.
*/
@@ -226,9 +235,8 @@
// TODO(b/119613670): log metrics
@GuardedBy("mLock")
public void startSessionLocked(@NonNull IBinder activityToken,
- @NonNull ActivityPresentationInfo activityPresentationInfo,
- @NonNull String sessionId, int uid, int flags,
- @NonNull IResultReceiver clientReceiver) {
+ @NonNull ActivityPresentationInfo activityPresentationInfo, int sessionId, int uid,
+ int flags, @NonNull IResultReceiver clientReceiver) {
if (activityPresentationInfo == null) {
Slog.w(TAG, "basic activity info is null");
setClientState(clientReceiver, STATE_DISABLED | STATE_INTERNAL_ERROR,
@@ -238,7 +246,8 @@
final int taskId = activityPresentationInfo.taskId;
final int displayId = activityPresentationInfo.displayId;
final ComponentName componentName = activityPresentationInfo.componentName;
- final boolean whiteListed = isWhitelistedLocked(componentName);
+ final boolean whiteListed = mMaster.mGlobalContentCaptureOptions.isWhitelisted(mUserId,
+ componentName);
final ComponentName serviceComponentName = getServiceComponentName();
final boolean enabled = isEnabledLocked();
if (mMaster.mRequestsHistory != null) {
@@ -315,14 +324,9 @@
newSession.notifySessionStartedLocked(clientReceiver);
}
- @GuardedBy("mLock")
- private boolean isWhitelistedLocked(@NonNull ComponentName componentName) {
- return mWhitelistHelper.isWhitelisted(componentName);
- }
-
// TODO(b/119613670): log metrics
@GuardedBy("mLock")
- public void finishSessionLocked(@NonNull String sessionId) {
+ public void finishSessionLocked(int sessionId) {
if (!isEnabledLocked()) {
return;
}
@@ -386,8 +390,8 @@
@GuardedBy("mLock")
public boolean sendActivityAssistDataLocked(@NonNull IBinder activityToken,
@NonNull Bundle data) {
- final String id = getSessionId(activityToken);
- if (id != null) {
+ final int id = getSessionId(activityToken);
+ if (id != NO_SESSION_ID) {
final ContentCaptureServerSession session = mSessions.get(id);
final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
final AssistStructure assistStructure = data.getParcelable(ASSIST_KEY_STRUCTURE);
@@ -403,7 +407,7 @@
}
@GuardedBy("mLock")
- public void removeSessionLocked(@NonNull String sessionId) {
+ public void removeSessionLocked(int sessionId) {
mSessions.remove(sessionId);
}
@@ -480,7 +484,7 @@
return null;
}
}
- ContentCaptureOptions options = new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel,
+ final ContentCaptureOptions options = new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel,
mMaster.mDevCfgMaxBufferSize, mMaster.mDevCfgIdleFlushingFrequencyMs,
mMaster.mDevCfgTextChangeFlushingFrequencyMs, mMaster.mDevCfgLogHistorySize,
whitelistedComponents);
@@ -491,6 +495,13 @@
}
@GuardedBy("mLock")
+ @Nullable
+ ArraySet<ContentCaptureCondition> getContentCaptureConditionsLocked(
+ @NonNull String packageName) {
+ return mConditionsByPkg.get(packageName);
+ }
+
+ @GuardedBy("mLock")
void onActivityEventLocked(@NonNull ComponentName componentName, @ActivityEventType int type) {
if (mRemoteService == null) {
if (mMaster.debug) Slog.d(mTag, "onActivityEvent(): no remote service");
@@ -522,9 +533,7 @@
mRemoteService.dump(prefix2, pw);
}
- mWhitelistHelper.dump(prefix, "Whitelist", pw);
-
- if (mSessions.isEmpty()) {
+ if (mSessions.size() == 0) {
pw.print(prefix); pw.println("no sessions");
} else {
final int sessionsSize = mSessions.size();
@@ -542,14 +551,14 @@
* Returns the session id associated with the given activity.
*/
@GuardedBy("mLock")
- private String getSessionId(@NonNull IBinder activityToken) {
+ private int getSessionId(@NonNull IBinder activityToken) {
for (int i = 0; i < mSessions.size(); i++) {
ContentCaptureServerSession session = mSessions.valueAt(i);
if (session.isActivitySession(activityToken)) {
return mSessions.keyAt(i);
}
}
- return null;
+ return NO_SESSION_ID;
}
/**
@@ -560,7 +569,7 @@
if (mMaster.verbose) {
Slog.v(TAG, "resetting content capture whitelist");
}
- mWhitelistHelper.setWhitelist((List) null, null);
+ mMaster.mGlobalContentCaptureOptions.resetWhitelist(mUserId);
}
private final class ContentCaptureServiceRemoteCallback extends
@@ -576,9 +585,24 @@
+ ", " + (activities == null
? "null_activities" : activities.size() + " activities") + ")");
}
- synchronized (mLock) {
- mWhitelistHelper.setWhitelist(packages, activities);
+ mMaster.mGlobalContentCaptureOptions.setWhitelist(mUserId, packages, activities);
+ }
+
+ @Override
+ public void setContentCaptureConditions(String packageName,
+ List<ContentCaptureCondition> conditions) {
+ if (mMaster.verbose) {
+ Slog.v(TAG, "setContentCaptureConditions(" + packageName + "): "
+ + (conditions == null ? "null" : conditions.size() + " conditions"));
}
+ synchronized (mLock) {
+ if (conditions == null) {
+ mConditionsByPkg.remove(packageName);
+ } else {
+ mConditionsByPkg.put(packageName, new ArraySet<>(conditions));
+ }
+ }
+ // TODO(b/119613670): log metrics
}
@Override
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index 9b2c05f..1ad66d8 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -16,6 +16,7 @@
package com.android.server.contentcapture;
import static android.service.contentcapture.ContentCaptureService.setClientState;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
import static android.view.contentcapture.ContentCaptureSession.STATE_ACTIVE;
import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
import static android.view.contentcapture.ContentCaptureSession.STATE_SERVICE_RESURRECTED;
@@ -57,7 +58,7 @@
/**
* Canonical session id.
*/
- private final String mId;
+ private final int mId;
/**
* UID of the app whose contents is being captured.
@@ -66,11 +67,12 @@
ContentCaptureServerSession(@NonNull IBinder activityToken,
@NonNull ContentCapturePerUserService service, @NonNull ComponentName appComponentName,
- @NonNull IResultReceiver sessionStateReceiver,
- int taskId, int displayId, @NonNull String sessionId, int uid, int flags) {
+ @NonNull IResultReceiver sessionStateReceiver, int taskId, int displayId, int sessionId,
+ int uid, int flags) {
+ Preconditions.checkArgument(sessionId != NO_SESSION_ID);
mActivityToken = activityToken;
mService = service;
- mId = Preconditions.checkNotNull(sessionId);
+ mId = sessionId;
mUid = uid;
mContentCaptureContext = new ContentCaptureContext(/* clientContext= */ null,
appComponentName, taskId, displayId, flags);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 0afe252..3fa3fdf 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -98,9 +98,8 @@
* Called by {@link ContentCaptureServerSession} to generate a call to the
* {@link RemoteContentCaptureService} to indicate the session was created.
*/
- public void onSessionStarted(@Nullable ContentCaptureContext context,
- @NonNull String sessionId, int uid, @NonNull IResultReceiver clientReceiver,
- int initialState) {
+ public void onSessionStarted(@Nullable ContentCaptureContext context, int sessionId, int uid,
+ @NonNull IResultReceiver clientReceiver, int initialState) {
scheduleAsyncRequest(
(s) -> s.onSessionStarted(context, sessionId, uid, clientReceiver, initialState));
}
@@ -109,15 +108,14 @@
* Called by {@link ContentCaptureServerSession} to generate a call to the
* {@link RemoteContentCaptureService} to indicate the session was finished.
*/
- public void onSessionFinished(@NonNull String sessionId) {
+ public void onSessionFinished(int sessionId) {
scheduleAsyncRequest((s) -> s.onSessionFinished(sessionId));
}
/**
* Called by {@link ContentCaptureServerSession} to send snapshot data to the service.
*/
- public void onActivitySnapshotRequest(@NonNull String sessionId,
- @NonNull SnapshotData snapshotData) {
+ public void onActivitySnapshotRequest(int sessionId, @NonNull SnapshotData snapshotData) {
scheduleAsyncRequest((s) -> s.onActivitySnapshot(sessionId, snapshotData));
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index c154240..9e1b3b8 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -51,6 +51,7 @@
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
"android.hidl.manager-V1.2-java",
+ "dnsresolver_aidl_interface-java",
"netd_aidl_interface-java",
"netd_event_listener_interface-java",
],
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 39f7f0f..6a9f5b6 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -357,10 +357,27 @@
&& (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
}
+ private boolean shouldShutdownLocked() {
+ if (mHealthInfo.batteryLevel > 0) {
+ return false;
+ }
+
+ // Battery-less devices should not shutdown.
+ if (!mHealthInfo.batteryPresent) {
+ return false;
+ }
+
+ // If battery state is not CHARGING, shutdown.
+ // - If battery present and state == unknown, this is an unexpected error state.
+ // - If level <= 0 and state == full, this is also an unexpected state
+ // - All other states (NOT_CHARGING, DISCHARGING) means it is not charging.
+ return mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_CHARGING;
+ }
+
private void shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
// wait until the system has booted before attempting to display the shutdown dialog.
- if (mHealthInfo.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+ if (shouldShutdownLocked()) {
mHandler.post(new Runnable() {
@Override
public void run() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2be92cd..1169eeb 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -63,6 +63,7 @@
import android.net.ConnectivityManager;
import android.net.ICaptivePortal;
import android.net.IConnectivityManager;
+import android.net.IDnsResolver;
import android.net.IIpConnectivityMetrics;
import android.net.INetd;
import android.net.INetdEventCallback;
@@ -294,6 +295,8 @@
private INetworkManagementService mNMS;
@VisibleForTesting
+ protected IDnsResolver mDnsResolver;
+ @VisibleForTesting
protected INetd mNetd;
private INetworkStatsService mStatsService;
private INetworkPolicyManager mPolicyManager;
@@ -525,6 +528,11 @@
return sMagicDecoderRing.get(what, Integer.toString(what));
}
+ private static IDnsResolver getDnsResolver() {
+ return IDnsResolver.Stub
+ .asInterface(ServiceManager.getService("dnsresolver"));
+ }
+
/** Handler thread used for both of the handlers below. */
@VisibleForTesting
protected final HandlerThread mHandlerThread;
@@ -810,13 +818,14 @@
public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
- this(context, netManager, statsService, policyManager, new IpConnectivityLog());
+ this(context, netManager, statsService, policyManager,
+ getDnsResolver(), new IpConnectivityLog());
}
@VisibleForTesting
protected ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
- IpConnectivityLog logger) {
+ IDnsResolver dnsresolver, IpConnectivityLog logger) {
if (DBG) log("ConnectivityService starting up");
mSystemProperties = getSystemProperties();
@@ -853,6 +862,7 @@
mPolicyManagerInternal = checkNotNull(
LocalServices.getService(NetworkPolicyManagerInternal.class),
"missing NetworkPolicyManagerInternal");
+ mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
mProxyTracker = makeProxyTracker();
mNetd = NetdService.getInstance();
@@ -1006,7 +1016,7 @@
mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler);
- mDnsManager = new DnsManager(mContext, mNMS, mSystemProperties);
+ mDnsManager = new DnsManager(mContext, mDnsResolver, mSystemProperties);
registerPrivateDnsSettingsCallbacks();
}
@@ -3021,9 +3031,9 @@
// NetworkFactories, so network traffic isn't interrupted for an unnecessarily
// long time.
try {
- mNMS.removeNetwork(nai.network.netId);
- } catch (Exception e) {
- loge("Exception removing network: " + e);
+ mNetd.networkDestroy(nai.network.netId);
+ } catch (RemoteException | ServiceSpecificException e) {
+ loge("Exception destroying network: " + e);
}
mDnsManager.removeNetwork(nai.network);
}
@@ -5372,8 +5382,8 @@
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
- mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS,
- factorySerialNumber);
+ mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver,
+ mNMS, factorySerialNumber);
// Make sure the network capabilities reflect what the agent info says.
nai.networkCapabilities = mixInCapabilities(nai, nc);
final String extraInfo = networkInfo.getExtraInfo();
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 2ded1e5..be58389 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -323,16 +323,24 @@
});
mPackageManager.addOnPermissionsChangeListener(
uid -> {
- synchronized (mLock) {
- onPermissionsChangedLocked();
- }
+ // listener invoked on ui thread, move to our thread to reduce risk of blocking
+ // ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onPermissionsChangedLocked();
+ }
+ });
});
mActivityManager.addOnUidImportanceListener(
(uid, importance) -> {
- synchronized (mLock) {
- onUidImportanceChangedLocked(uid, importance);
- }
+ // listener invoked on ui thread, move to our thread to reduce risk of blocking
+ // ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onUidImportanceChangedLocked(uid, importance);
+ }
+ });
},
FOREGROUND_IMPORTANCE_CUTOFF);
mContext.getContentResolver().registerContentObserver(
@@ -394,9 +402,13 @@
LocalServices.getService(PowerManagerInternal.class);
localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
state -> {
- synchronized (mLock) {
- onBatterySaverModeChangedLocked(state.locationMode);
- }
+ // listener invoked on ui thread, move to our thread to reduce risk of blocking
+ // ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onBatterySaverModeChangedLocked(state.locationMode);
+ }
+ });
});
new PackageMonitor() {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 61a7182..d1ae284 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1610,20 +1610,6 @@
}
@Override
- public void setDnsConfigurationForNetwork(int netId, String[] servers, String[] domains,
- int[] params, String tlsHostname, String[] tlsServers) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- final String[] tlsFingerprints = new String[0];
- try {
- mNetdService.setResolverConfiguration(
- netId, servers, domains, params, tlsHostname, tlsServers, tlsFingerprints);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
public void addVpnUidRanges(int netId, UidRange[] ranges) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -2082,21 +2068,6 @@
}
@Override
- public void removeNetwork(int netId) {
- mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
-
- try {
- mNetdService.networkDestroy(netId);
- } catch (ServiceSpecificException e) {
- Log.w(TAG, "removeNetwork(" + netId + "): ", e);
- throw e;
- } catch (RemoteException e) {
- Log.w(TAG, "removeNetwork(" + netId + "): ", e);
- throw e.rethrowAsRuntimeException();
- }
- }
-
- @Override
public void addInterfaceToNetwork(String iface, int netId) {
modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, netId, iface);
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1a842f7..b3a667a 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3947,6 +3947,23 @@
case "ak.alizandro.smartaudiobookplayer": // b/129084042
case "com.campmobile.snow": // b/128803870
case "com.qnap.qfile": // b/126374406
+ case "com.google.android.apps.photos": // b/125506293
+ case "com.facebook.mlite": // b/126561155
+ case "com.ss.android.ugc.trill": // b/126610656
+ case "com.instagram.android": // b/127526615
+ case "com.facebook.orca": // b/128255453
+ case "org.videolan.vlc": // b/128391743
+ case "vStudio.Android.Camera360": // b/128882110
+ case "com.twitter.android": // b/128948908
+ case "com.tumblr": // b/129022664
+ case "com.sina.weibo": // b/129029018
+ case "com.kwai.video": // b/129037235
+ case "com.fotoable.photocollage": // b/129236353
+ case "com.xvideostudio.videoeditor": // b/129247146
+ case "app.buzz.share": // b/129304005
+ case "com.ss.android.article.topbuzzvideo.en": // b/129303979
+ case "com.linecorp.b612.android": // b/129318512
+ case "com.google.android.GoogleCamera": // b/128326994
return true;
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 8b10267..1c99316 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -79,6 +79,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.OptionalInt;
+import java.util.stream.Collectors;
/**
* Since phone process can be restarted, this class provides a centralized place
@@ -260,8 +261,7 @@
static final int ENFORCE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
| PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
- | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
- | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
+ | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST;
static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
@@ -627,11 +627,6 @@
r.callingPackage = callingPackage;
r.callerUid = Binder.getCallingUid();
r.callerPid = Binder.getCallingPid();
- if (r.subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && r.subId != subId) {
- throw new IllegalArgumentException(
- "PhoneStateListener cannot concurrently listen on multiple " +
- "subscriptions. Previously registered on subId: " + r.subId);
- }
// Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
// force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -827,7 +822,10 @@
}
}
if ((events & PhoneStateListener
- .LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0) {
+ .LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0
+ && TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(
+ r.context, r.callerPid, r.callerUid, r.callingPackage,
+ "listen_active_data_subid_change")) {
try {
r.callback.onActiveDataSubIdChanged(mActiveDataSubId);
} catch (RemoteException ex) {
@@ -1769,12 +1767,23 @@
log("notifyActiveDataSubIdChanged: activeDataSubId=" + activeDataSubId);
}
+ // Create a copy to prevent the IPC call while checking carrier privilege under the lock.
+ List<Record> copiedRecords;
synchronized (mRecords) {
- mActiveDataSubId = activeDataSubId;
+ copiedRecords = new ArrayList<>(mRecords);
+ }
+ mActiveDataSubId = activeDataSubId;
- for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE)) {
+ // Filter the record that does not listen to this change or does not have the permission.
+ copiedRecords = copiedRecords.stream().filter(r -> r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE)
+ && TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(
+ mContext, r.callerPid, r.callerUid, r.callingPackage,
+ "notifyActiveDataSubIdChanged")).collect(Collectors.toCollection(ArrayList::new));
+
+ synchronized (mRecords) {
+ for (Record r : copiedRecords) {
+ if (mRecords.contains(r)) {
try {
r.callback.onActiveDataSubIdChanged(activeDataSubId);
} catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 8ccb6e2..9325d25 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -307,7 +307,6 @@
}
cancelJobToUpdateAdbKeyStore();
- mAdbKeyStore = null;
mConnectedKey = null;
break;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index cef245b..261ed4c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1524,8 +1524,9 @@
boolean anyClientActivities = false;
for (int i=proc.services.size()-1; i>=0 && !anyClientActivities; i--) {
ServiceRecord sr = proc.services.valueAt(i);
- for (int conni=sr.connections.size()-1; conni>=0 && !anyClientActivities; conni--) {
- ArrayList<ConnectionRecord> clist = sr.connections.valueAt(conni);
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = sr.getConnections();
+ for (int conni = connections.size() - 1; conni >= 0 && !anyClientActivities; conni--) {
+ ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
for (int cri=clist.size()-1; cri>=0; cri--) {
ConnectionRecord cr = clist.get(cri);
if (cr.binding.client == null || cr.binding.client == proc) {
@@ -1752,10 +1753,10 @@
callerApp.uid, callerApp.processName, callingPackage);
IBinder binder = connection.asBinder();
- ArrayList<ConnectionRecord> clist = s.connections.get(binder);
+ ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
- s.connections.put(binder, clist);
+ s.putConnection(binder, clist);
}
clist.add(c);
b.connections.add(c);
@@ -1855,8 +1856,9 @@
b.binder = service;
b.requested = true;
b.received = true;
- for (int conni=r.connections.size()-1; conni>=0; conni--) {
- ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+ for (int conni = connections.size() - 1; conni >= 0; conni--) {
+ ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
@@ -2722,6 +2724,10 @@
updateServiceClientActivitiesLocked(app, null, true);
+ if (newService && created) {
+ app.addBoundClientUidsOfNewService(r);
+ }
+
// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
@@ -2881,8 +2887,9 @@
// Report to all of the connections that the service is no longer
// available.
- for (int conni=r.connections.size()-1; conni>=0; conni--) {
- ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+ for (int conni = connections.size() - 1; conni >= 0; conni--) {
+ ArrayList<ConnectionRecord> c = connections.valueAt(conni);
for (int i=0; i<c.size(); i++) {
ConnectionRecord cr = c.get(i);
// There is still a connection to the service that is
@@ -3013,6 +3020,7 @@
r.stats.stopLaunchedLocked();
}
r.app.services.remove(r);
+ r.app.updateBoundClientUids();
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
}
@@ -3065,11 +3073,11 @@
IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding;
ServiceRecord s = b.service;
- ArrayList<ConnectionRecord> clist = s.connections.get(binder);
+ ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
- s.connections.remove(binder);
+ s.removeConnection(binder);
}
}
b.connections.remove(c);
@@ -3294,6 +3302,7 @@
if (finishing) {
if (r.app != null && !r.app.isPersistent()) {
r.app.services.remove(r);
+ r.app.updateBoundClientUids();
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
}
@@ -3389,6 +3398,7 @@
Slog.i(TAG, " Force stopping service " + service);
if (service.app != null && !service.app.isPersistent()) {
service.app.services.remove(service);
+ service.app.updateBoundClientUids();
if (service.whitelistManager) {
updateWhitelistManagerLocked(service.app);
}
@@ -3504,8 +3514,9 @@
Iterator<ServiceRecord> it = app.services.iterator();
while (it.hasNext()) {
ServiceRecord r = it.next();
- for (int conni=r.connections.size()-1; conni>=0; conni--) {
- ArrayList<ConnectionRecord> cl = r.connections.valueAt(conni);
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+ for (int conni=connections.size()-1; conni>=0; conni--) {
+ ArrayList<ConnectionRecord> cl = connections.valueAt(conni);
for (int i=0; i<cl.size(); i++) {
ConnectionRecord c = cl.get(i);
if (c.binding.client != app) {
@@ -3542,6 +3553,7 @@
}
if (sr.app != app && sr.app != null && !sr.app.isPersistent()) {
sr.app.services.remove(sr);
+ sr.app.updateBoundClientUids();
}
sr.setProcess(null);
sr.isolatedProc = null;
@@ -3605,6 +3617,7 @@
// so make sure the service is cleaned out of it.
if (!app.isPersistent()) {
app.services.removeAt(i);
+ app.updateBoundClientUids();
}
// Sanity check: if the service listed for the app is not one
@@ -3655,6 +3668,7 @@
if (!allowRestart) {
app.services.clear();
+ app.clearBoundClientUids();
// Make sure there are no more restarting services for this process.
for (int i=mRestartingServices.size()-1; i>=0; i--) {
@@ -3701,7 +3715,7 @@
info.foreground = r.isForeground;
info.activeSince = r.createRealTime;
info.started = r.startRequested;
- info.clientCount = r.connections.size();
+ info.clientCount = r.getConnections().size();
info.crashCount = r.crashCount;
info.lastActivityTime = r.lastActivity;
if (r.isForeground) {
@@ -3717,8 +3731,9 @@
info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
}
- for (int conni=r.connections.size()-1; conni>=0; conni--) {
- ArrayList<ConnectionRecord> connl = r.connections.valueAt(conni);
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+ for (int conni = connections.size() - 1; conni >= 0; conni--) {
+ ArrayList<ConnectionRecord> connl = connections.valueAt(conni);
for (int i=0; i<connl.size(); i++) {
ConnectionRecord conn = connl.get(i);
if (conn.clientLabel != 0) {
@@ -3787,9 +3802,10 @@
public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
int userId = UserHandle.getUserId(Binder.getCallingUid());
ServiceRecord r = getServiceByNameLocked(name, userId);
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
if (r != null) {
- for (int conni=r.connections.size()-1; conni>=0; conni--) {
- ArrayList<ConnectionRecord> conn = r.connections.valueAt(conni);
+ for (int conni = connections.size() - 1; conni >= 0; conni--) {
+ ArrayList<ConnectionRecord> conn = connections.valueAt(conni);
for (int i=0; i<conn.size(); i++) {
if (conn.get(i).clientIntent != null) {
return conn.get(i).clientIntent;
@@ -4080,11 +4096,12 @@
pw.print(" started=");
pw.print(r.startRequested);
pw.print(" connections=");
- pw.println(r.connections.size());
- if (r.connections.size() > 0) {
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+ pw.println(connections.size());
+ if (connections.size() > 0) {
pw.println(" Connections:");
- for (int conni=0; conni<r.connections.size(); conni++) {
- ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
+ for (int conni = 0; conni < connections.size(); conni++) {
+ ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
for (int i = 0; i < clist.size(); i++) {
ConnectionRecord conn = clist.get(i);
pw.print(" ");
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 1751856..b759dd4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -20,8 +20,10 @@
import android.app.ActivityThread;
import android.content.ContentResolver;
+import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
+import android.os.Build;
import android.os.Handler;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.OnPropertyChangedListener;
@@ -38,6 +40,7 @@
* Settings constants that can modify the activity manager's behavior.
*/
final class ActivityManagerConstants extends ContentObserver {
+ private static final String TAG = "ActivityManagerConstants";
// Key names stored in the settings value.
private static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
@@ -272,6 +275,16 @@
// memory trimming.
public int CUR_TRIM_CACHED_PROCESSES;
+ private static final long MIN_AUTOMATIC_HEAP_DUMP_PSS_THRESHOLD_BYTES = 100 * 1024; // 100 KB
+
+ private final boolean mSystemServerAutomaticHeapDumpEnabled;
+
+ /** Package to report to when the memory usage exceeds the limit. */
+ private final String mSystemServerAutomaticHeapDumpPackageName;
+
+ /** Byte limit for dump heap monitoring. */
+ private long mSystemServerAutomaticHeapDumpPssThresholdBytes;
+
private static final Uri ACTIVITY_MANAGER_CONSTANTS_URI = Settings.Global.getUriFor(
Settings.Global.ACTIVITY_MANAGER_CONSTANTS);
@@ -286,6 +299,9 @@
Settings.Global.getUriFor(
Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST);
+ private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
+ Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
+
private final OnPropertyChangedListener mOnDeviceConfigChangedListener =
new OnPropertyChangedListener() {
@Override
@@ -296,9 +312,17 @@
}
};
- public ActivityManagerConstants(ActivityManagerService service, Handler handler) {
+ ActivityManagerConstants(Context context, ActivityManagerService service, Handler handler) {
super(handler);
mService = service;
+ mSystemServerAutomaticHeapDumpEnabled = Build.IS_DEBUGGABLE
+ && context.getResources().getBoolean(
+ com.android.internal.R.bool.config_debugEnableAutomaticSystemServerHeapDumps);
+ mSystemServerAutomaticHeapDumpPackageName = context.getPackageName();
+ mSystemServerAutomaticHeapDumpPssThresholdBytes = Math.max(
+ MIN_AUTOMATIC_HEAP_DUMP_PSS_THRESHOLD_BYTES,
+ context.getResources().getInteger(
+ com.android.internal.R.integer.config_debugSystemServerPssThresholdBytes));
}
public void start(ContentResolver resolver) {
@@ -308,10 +332,17 @@
mResolver.registerContentObserver(BACKGROUND_ACTIVITY_STARTS_ENABLED_URI, false, this);
mResolver.registerContentObserver(BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI,
false, this);
+ if (mSystemServerAutomaticHeapDumpEnabled) {
+ mResolver.registerContentObserver(ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI,
+ false, this);
+ }
updateConstants();
updateActivityStartsLoggingEnabled();
updateBackgroundActivityStartsEnabled();
updateBackgroundActivityStartsPackageNamesWhitelist();
+ if (mSystemServerAutomaticHeapDumpEnabled) {
+ updateEnableAutomaticSystemServerHeapDumps();
+ }
DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ActivityThread.currentApplication().getMainExecutor(),
mOnDeviceConfigChangedListener);
@@ -343,6 +374,8 @@
updateBackgroundActivityStartsEnabled();
} else if (BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI.equals(uri)) {
updateBackgroundActivityStartsPackageNamesWhitelist();
+ } else if (ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI.equals(uri)) {
+ updateEnableAutomaticSystemServerHeapDumps();
}
}
@@ -450,6 +483,24 @@
mPackageNamesWhitelistedForBgActivityStarts = newSet;
}
+ private void updateEnableAutomaticSystemServerHeapDumps() {
+ if (!mSystemServerAutomaticHeapDumpEnabled) {
+ Slog.wtf(TAG,
+ "updateEnableAutomaticSystemServerHeapDumps called when leak detection "
+ + "disabled");
+ return;
+ }
+ // Monitoring is on by default, so if the setting hasn't been set by the user,
+ // monitoring should be on.
+ final boolean enabled = Settings.Global.getInt(mResolver,
+ Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS, 1) == 1;
+
+ // Setting the threshold to 0 stops the checking.
+ final long threshold = enabled ? mSystemServerAutomaticHeapDumpPssThresholdBytes : 0;
+ mService.setDumpHeapDebugLimit(null, 0, threshold,
+ mSystemServerAutomaticHeapDumpPackageName);
+ }
+
private void updateMaxCachedProcesses() {
String maxCachedProcessesFlag = DeviceConfig.getProperty(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_MAX_CACHED_PROCESSES);
@@ -460,7 +511,7 @@
: mOverrideMaxCachedProcesses;
} catch (NumberFormatException e) {
// Bad flag value from Phenotype, revert to default.
- Slog.e("ActivityManagerConstants",
+ Slog.e(TAG,
"Unable to parse flag for max_cached_processes: " + maxCachedProcessesFlag, e);
CUR_MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 05ec954..f51589a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2288,7 +2288,8 @@
mBatteryStatsService = null;
mHandler = hasHandlerThread ? new MainHandler(handlerThread.getLooper()) : null;
mHandlerThread = handlerThread;
- mConstants = hasHandlerThread ? new ActivityManagerConstants(this, mHandler) : null;
+ mConstants = hasHandlerThread
+ ? new ActivityManagerConstants(mContext, this, mHandler) : null;
final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */);
mProcessList.init(this, activeUids);
mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
@@ -2336,7 +2337,7 @@
mProcStartHandlerThread.start();
mProcStartHandler = new Handler(mProcStartHandlerThread.getLooper());
- mConstants = new ActivityManagerConstants(this, mHandler);
+ mConstants = new ActivityManagerConstants(mContext, this, mHandler);
final ActiveUids activeUids = new ActiveUids(this, true /* postChangesToAtm */);
mProcessList.init(this, activeUids);
mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
@@ -8835,7 +8836,6 @@
mAtmInternal.updateTopComponentForFactoryTest();
retrieveSettings();
- final int currentUserId = mUserController.getCurrentUserId();
mUgmInternal.onSystemReady();
final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
@@ -8849,6 +8849,16 @@
}
if (goingCallback != null) goingCallback.run();
+ // Check the current user here as a user can be started inside goingCallback.run() from
+ // other system services.
+ final int currentUserId = mUserController.getCurrentUserId();
+ Slog.i(TAG, "Current user:" + currentUserId);
+ if (currentUserId != UserHandle.USER_SYSTEM && !mUserController.isSystemUserStarted()) {
+ // User other than system user has started. Make sure that system user is already
+ // started before switching user.
+ throw new RuntimeException("System user not started while current user is:"
+ + currentUserId);
+ }
traceLog.traceBegin("ActivityManagerStartApps");
mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
Integer.toString(currentUserId), currentUserId);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index c1b9a20..924e331 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -53,12 +53,14 @@
import android.content.Context;
import android.os.Binder;
import android.os.Debug;
+import android.os.IBinder;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -1110,12 +1112,13 @@
}
}
- for (int conni = s.connections.size() - 1;
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
+ for (int conni = serviceConnections.size() - 1;
conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
|| procState > ActivityManager.PROCESS_STATE_TOP);
conni--) {
- ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
+ ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
for (int i = 0;
i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a90e994..ce13cd8 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -259,6 +259,8 @@
// A set of tokens that currently contribute to this process being temporarily whitelisted
// to start activities even if it's not in the foreground
final ArraySet<Binder> mAllowBackgroundActivityStartsTokens = new ArraySet<>();
+ // a set of UIDs of all bound clients
+ private ArraySet<Integer> mBoundClientUids = new ArraySet<>();
String isolatedEntryPoint; // Class to run on start if this is a special isolated process.
String[] isolatedEntryPointArgs; // Arguments to pass to isolatedEntryPoint's main().
@@ -1193,6 +1195,53 @@
!mAllowBackgroundActivityStartsTokens.isEmpty());
}
+ void addBoundClientUids(ArraySet<Integer> clientUids) {
+ mBoundClientUids.addAll(clientUids);
+ mWindowProcessController.setBoundClientUids(mBoundClientUids);
+ }
+
+ void updateBoundClientUids() {
+ if (services.isEmpty()) {
+ clearBoundClientUids();
+ return;
+ }
+ // grab a set of clientUids of all connections of all services
+ ArraySet<Integer> boundClientUids = new ArraySet<>();
+ final int K = services.size();
+ for (int j = 0; j < K; j++) {
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
+ services.valueAt(j).getConnections();
+ final int N = conns.size();
+ for (int conni = 0; conni < N; conni++) {
+ ArrayList<ConnectionRecord> c = conns.valueAt(conni);
+ for (int i = 0; i < c.size(); i++) {
+ boundClientUids.add(c.get(i).clientUid);
+ }
+ }
+ }
+ mBoundClientUids = boundClientUids;
+ mWindowProcessController.setBoundClientUids(mBoundClientUids);
+ }
+
+ void addBoundClientUidsOfNewService(ServiceRecord sr) {
+ if (sr == null) {
+ return;
+ }
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns = sr.getConnections();
+ for (int conni = conns.size() - 1; conni >= 0; conni--) {
+ ArrayList<ConnectionRecord> c = conns.valueAt(conni);
+ for (int i = 0; i < c.size(); i++) {
+ mBoundClientUids.add(c.get(i).clientUid);
+ }
+ }
+ mWindowProcessController.setBoundClientUids(mBoundClientUids);
+ }
+
+ void clearBoundClientUids() {
+ mBoundClientUids.clear();
+ mWindowProcessController.setBoundClientUids(mBoundClientUids);
+ }
+
void setActiveInstrumentation(ActiveInstrumentation instr) {
mInstr = instr;
boolean isInstrumenting = instr != null;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index eeaa7de..217fd6d 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -38,6 +38,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -88,7 +89,7 @@
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
= new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
// All active bindings to the service.
- final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
+ private final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
= new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();
// IBinder -> ConnectionRecord of all bound clients
@@ -542,6 +543,7 @@
}
} else if (app != null) {
app.removeAllowBackgroundActivityStartsToken(this);
+ app.updateBoundClientUids();
}
app = _proc;
if (pendingConnectionGroup > 0 && _proc != null) {
@@ -563,6 +565,33 @@
}
}
}
+ if (_proc != null) {
+ _proc.updateBoundClientUids();
+ }
+ }
+
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> getConnections() {
+ return connections;
+ }
+
+ void putConnection(IBinder binder, ArrayList<ConnectionRecord> clist) {
+ connections.put(binder, clist);
+ // if we have a process attached, add bound client uids of this connection to it
+ if (app != null) {
+ ArraySet<Integer> boundClientUids = new ArraySet<>();
+ for (int i = 0; i < clist.size(); i++) {
+ boundClientUids.add(clist.get(i).clientUid);
+ }
+ app.addBoundClientUids(boundClientUids);
+ }
+ }
+
+ void removeConnection(IBinder binder) {
+ connections.remove(binder);
+ // if we have a process attached, tell it to update the state of bound clients
+ if (app != null) {
+ app.updateBoundClientUids();
+ }
}
void updateHasBindingWhitelistingBgActivityStarts() {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 07c9cca..cc4116e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -956,15 +956,26 @@
final int oldUserId = getCurrentUserId();
if (oldUserId == userId) {
final UserState state = getStartedUserState(userId);
- if (state != null && state.state == STATE_RUNNING_UNLOCKED) {
- // We'll skip all later code, so we must tell listener it's already unlocked.
- try {
- unlockListener.onFinished(userId, null);
- } catch (RemoteException ignore) {
- // Ignore.
+ if (state == null) {
+ Slog.wtf(TAG, "Current user has no UserState");
+ // continue starting.
+ } else {
+ if (userId == UserHandle.USER_SYSTEM && state.state == STATE_BOOTING) {
+ // system user start explicitly requested. should continue starting as it
+ // is not in running state.
+ } else {
+ if (state.state == STATE_RUNNING_UNLOCKED) {
+ // We'll skip all later code, so we must tell listener it's already
+ // unlocked.
+ try {
+ unlockListener.onFinished(userId, null);
+ } catch (RemoteException ignore) {
+ // Ignore.
+ }
+ }
+ return true;
}
}
- return true;
}
if (foreground) {
@@ -1743,6 +1754,24 @@
return state.state != UserState.STATE_STOPPING && state.state != UserState.STATE_SHUTDOWN;
}
+ /**
+ * Check if system user is already started. Unlike other user, system user is in STATE_BOOTING
+ * even if it is not explicitly started. So isUserRunning cannot give the right state
+ * to check if system user is started or not.
+ * @return true if system user is started.
+ */
+ boolean isSystemUserStarted() {
+ synchronized (mLock) {
+ UserState uss = mStartedUsers.get(UserHandle.USER_SYSTEM);
+ if (uss == null) {
+ return false;
+ }
+ return uss.state == UserState.STATE_RUNNING_LOCKED
+ || uss.state == UserState.STATE_RUNNING_UNLOCKING
+ || uss.state == UserState.STATE_RUNNING_UNLOCKED;
+ }
+ }
+
UserInfo getCurrentUser() {
if ((mInjector.checkCallingPermission(INTERACT_ACROSS_USERS)
!= PackageManager.PERMISSION_GRANTED) && (
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index b2c7ff3..87b272b 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -69,6 +69,9 @@
AudioEffect.Descriptor[] effects,
int activeSource, String packName) {
if (MediaRecorder.isSystemOnlyAudioSource(source)) {
+ // still want to log event, it just won't appear in recording configurations
+ sEventLogger.log(new RecordingEvent(event, uid, session, source, packName)
+ .printLog(TAG));
return;
}
String clientEffectName = clientEffects.length == 0 ? "None" : clientEffects[0].name;
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index b8810c8f..2df8982 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -24,6 +24,7 @@
import android.hardware.radio.ITuner;
import android.hardware.radio.ITunerCallback;
import android.hardware.radio.RadioManager;
+import android.hardware.radio.RadioTuner;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
import android.os.IHwBinder.DeathRecipient;
@@ -49,9 +50,17 @@
@GuardedBy("mLock")
private final Map<String, Integer> mServiceNameToModuleIdMap = new HashMap<>();
+ // Map from module ID to RadioModule created by mServiceListener.onRegistration().
@GuardedBy("mLock")
private final Map<Integer, RadioModule> mModules = new HashMap<>();
+ // Map from module ID to TunerSession created by openSession().
+ //
+ // Because this service currently implements a 1 AIDL to 1 HAL policy, mTunerSessions is used to
+ // enforce the "aggresive open" policy mandated for IBroadcastRadio.openSession(). In the
+ // future, this solution will be replaced with a multiple-AIDL to 1 HAL implementation.
+ private final Map<Integer, TunerSession> mTunerSessions = new HashMap<>();
+
private IServiceNotification.Stub mServiceListener = new IServiceNotification.Stub() {
@Override
public void onRegistration(String fqName, String serviceName, boolean preexisting) {
@@ -72,6 +81,7 @@
}
Slog.v(TAG, "loaded broadcast radio module " + moduleId + ": " + serviceName
+ " (HAL 2.0)");
+ closeTunerSessionLocked(moduleId);
mModules.put(moduleId, module);
if (newService) {
@@ -96,6 +106,7 @@
synchronized (mLock) {
int moduleId = (int) cookie;
mModules.remove(moduleId);
+ closeTunerSessionLocked(moduleId);
for (Map.Entry<String, Integer> entry : mServiceNameToModuleIdMap.entrySet()) {
if (entry.getValue() == moduleId) {
@@ -152,16 +163,20 @@
RadioModule module = null;
synchronized (mLock) {
module = mModules.get(moduleId);
- }
- if (module == null) {
- throw new IllegalArgumentException("Invalid module ID");
+ if (module == null) {
+ throw new IllegalArgumentException("Invalid module ID");
+ }
+ closeTunerSessionLocked(moduleId);
}
- TunerSession session = module.openSession(callback);
- if (legacyConfig != null) {
- session.setConfiguration(legacyConfig);
+ TunerSession tunerSession = module.openSession(callback);
+ synchronized (mLock) {
+ mTunerSessions.put(moduleId, tunerSession);
}
- return session;
+ if (legacyConfig != null) {
+ tunerSession.setConfiguration(legacyConfig);
+ }
+ return tunerSession;
}
public ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
@@ -183,4 +198,12 @@
}
return aggregator;
}
+
+ private void closeTunerSessionLocked(int moduleId) {
+ TunerSession tunerSession = mTunerSessions.remove(moduleId);
+ if (tunerSession != null) {
+ Slog.d(TAG, "Closing previous TunerSession");
+ tunerSession.close(RadioTuner.ERROR_HARDWARE_FAILURE);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 9833507..05ca144 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -17,6 +17,7 @@
package com.android.server.broadcastradio.hal2;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Bitmap;
import android.hardware.broadcastradio.V2_0.ConfigFlag;
import android.hardware.broadcastradio.V2_0.ITunerSession;
@@ -58,8 +59,22 @@
@Override
public void close() {
+ close(null);
+ }
+
+ /**
+ * Closes the TunerSession. If error is non-null, the client's onError() callback is invoked
+ * first with the specified error, see {@link
+ * android.hardware.radio.RadioTuner.Callback#onError}.
+ *
+ * @param error Optional error to send to client before session is closed.
+ */
+ public void close(@Nullable Integer error) {
synchronized (mLock) {
if (mIsClosed) return;
+ if (error != null) {
+ TunerCallback.dispatch(() -> mCallback.mClientCb.onError(error));
+ }
mIsClosed = true;
}
}
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index d8bb635..1913635 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -30,13 +30,15 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.net.IDnsResolver;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkUtils;
import android.net.Uri;
import android.net.shared.PrivateDnsConfig;
import android.os.Binder;
-import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -229,7 +231,7 @@
private final Context mContext;
private final ContentResolver mContentResolver;
- private final INetworkManagementService mNMS;
+ private final IDnsResolver mDnsResolver;
private final MockableSystemProperties mSystemProperties;
// TODO: Replace these Maps with SparseArrays.
private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap;
@@ -243,10 +245,10 @@
private String mPrivateDnsMode;
private String mPrivateDnsSpecifier;
- public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) {
+ public DnsManager(Context ctx, IDnsResolver dnsResolver, MockableSystemProperties sp) {
mContext = ctx;
mContentResolver = mContext.getContentResolver();
- mNMS = nms;
+ mDnsResolver = dnsResolver;
mSystemProperties = sp;
mPrivateDnsMap = new HashMap<>();
mPrivateDnsValidationMap = new HashMap<>();
@@ -260,6 +262,12 @@
}
public void removeNetwork(Network network) {
+ try {
+ mDnsResolver.clearResolverConfiguration(network.netId);
+ } catch (RemoteException | ServiceSpecificException e) {
+ Slog.e(TAG, "Error clearing DNS configuration: " + e);
+ return;
+ }
mPrivateDnsMap.remove(network.netId);
mPrivateDnsValidationMap.remove(network.netId);
}
@@ -344,10 +352,12 @@
Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs),
Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers)));
+ final String[] tlsFingerprints = new String[0];
try {
- mNMS.setDnsConfigurationForNetwork(
- netId, assignedServers, domainStrs, params, tlsHostname, tlsServers);
- } catch (Exception e) {
+ mDnsResolver.setResolverConfiguration(
+ netId, assignedServers, domainStrs, params,
+ tlsHostname, tlsServers, tlsFingerprints);
+ } catch (RemoteException | ServiceSpecificException e) {
Slog.e(TAG, "Error setting DNS configuration: " + e);
return;
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 262ba7a..66bd27c 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import android.net.ConnectivityManager;
+import android.net.IDnsResolver;
import android.net.INetd;
import android.net.InetAddresses;
import android.net.InterfaceConfiguration;
@@ -65,6 +66,7 @@
NetworkInfo.State.SUSPENDED,
};
+ private final IDnsResolver mDnsResolver;
private final INetd mNetd;
private final INetworkManagementService mNMService;
@@ -84,7 +86,9 @@
private Inet6Address mIPv6Address;
private State mState = State.IDLE;
- public Nat464Xlat(NetworkAgentInfo nai, INetd netd, INetworkManagementService nmService) {
+ public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver,
+ INetworkManagementService nmService) {
+ mDnsResolver = dnsResolver;
mNetd = netd;
mNMService = nmService;
mNetwork = nai;
@@ -269,7 +273,7 @@
private void startPrefixDiscovery() {
try {
- mNetd.resolverStartPrefix64Discovery(getNetId());
+ mDnsResolver.startPrefix64Discovery(getNetId());
mState = State.DISCOVERING;
} catch (RemoteException | ServiceSpecificException e) {
Slog.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e);
@@ -278,7 +282,7 @@
private void stopPrefixDiscovery() {
try {
- mNetd.resolverStopPrefix64Discovery(getNetId());
+ mDnsResolver.stopPrefix64Discovery(getNetId());
} catch (RemoteException | ServiceSpecificException e) {
Slog.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 8f2825c..e3fdbe8 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import android.content.Context;
+import android.net.IDnsResolver;
import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.LinkProperties;
@@ -255,7 +256,7 @@
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
NetworkMisc misc, ConnectivityService connService, INetd netd,
- INetworkManagementService nms, int factorySerialNumber) {
+ IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) {
this.messenger = messenger;
asyncChannel = ac;
network = net;
@@ -263,7 +264,7 @@
linkProperties = lp;
networkCapabilities = nc;
currentScore = score;
- clatd = new Nat464Xlat(this, netd, nms);
+ clatd = new Nat464Xlat(this, netd, dnsResolver, nms);
mConnService = connService;
mContext = context;
mHandler = handler;
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 0b1a98e..b140c1b 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -233,6 +233,10 @@
// permission is changed according to entitlement check result.
mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED, systemProperties);
+ mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
+ mLog.log("OBSERVED UiEnitlementFailed");
+ stopTethering(downstream);
+ });
mCarrierConfigChange = new VersionedBroadcastListener(
"CarrierConfigChangeListener", mContext, mHandler, filter,
@@ -405,21 +409,25 @@
}
private int setWifiTethering(final boolean enable) {
- int rval = TETHER_ERROR_MASTER_ERROR;
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mPublicSync) {
- mWifiTetherRequested = enable;
final WifiManager mgr = getWifiManager();
+ if (mgr == null) {
+ mLog.e("setWifiTethering: failed to get WifiManager!");
+ return TETHER_ERROR_SERVICE_UNAVAIL;
+ }
if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
(!enable && mgr.stopSoftAp())) {
- rval = TETHER_ERROR_NO_ERROR;
+ mWifiTetherRequested = enable;
+ return TETHER_ERROR_NO_ERROR;
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
- return rval;
+
+ return TETHER_ERROR_MASTER_ERROR;
}
private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
@@ -938,6 +946,11 @@
public int setUsbTethering(boolean enable) {
if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
+ if (usbManager == null) {
+ mLog.e("setUsbTethering: failed to get UsbManager!");
+ return TETHER_ERROR_SERVICE_UNAVAIL;
+ }
+
synchronized (mPublicSync) {
usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_RNDIS
: UsbManager.FUNCTION_NONE);
diff --git a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
index 5c45397..764a6eb 100644
--- a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -109,6 +109,7 @@
private boolean mCellularUpstreamPermitted = true;
private boolean mUsingCellularAsUpstream = false;
private boolean mNeedReRunProvisioningUi = false;
+ private OnUiEntitlementFailedListener mListener;
public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
@@ -129,6 +130,20 @@
null, mHandler);
}
+ public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) {
+ mListener = listener;
+ }
+
+ /** Callback fired when UI entitlement failed. */
+ public interface OnUiEntitlementFailedListener {
+ /**
+ * Ui entitlement check fails in |downstream|.
+ *
+ * @param downstream tethering type from ConnectivityManager.TETHERING_{@code *}.
+ */
+ void onUiEntitlementFailed(int downstream);
+ }
+
/**
* Pass a new TetheringConfiguration instance each time when
* Tethering#updateConfiguration() is called.
@@ -337,7 +352,9 @@
*/
protected void runSilentTetherProvisioning(int type) {
if (DBG) Log.d(TAG, "runSilentTetherProvisioning: " + type);
- ResultReceiver receiver = buildProxyReceiver(type, null);
+ // For silent provisioning, settings would stop tethering when entitlement fail.
+ ResultReceiver receiver = buildProxyReceiver(type,
+ false/* notifyFail */, null);
Intent intent = new Intent();
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
@@ -358,7 +375,8 @@
*/
@VisibleForTesting
protected void runUiTetherProvisioning(int type) {
- ResultReceiver receiver = buildProxyReceiver(type, null);
+ ResultReceiver receiver = buildProxyReceiver(type,
+ true/* notifyFail */, null);
runUiTetherProvisioning(type, receiver);
}
@@ -555,12 +573,16 @@
}
}
- private ResultReceiver buildProxyReceiver(int type, final ResultReceiver receiver) {
+ private ResultReceiver buildProxyReceiver(int type, boolean notifyFail,
+ final ResultReceiver receiver) {
ResultReceiver rr = new ResultReceiver(mHandler) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
addDownstreamMapping(type, updatedCacheValue);
+ if (updatedCacheValue == TETHER_ERROR_PROVISION_FAILED && notifyFail) {
+ mListener.onUiEntitlementFailed(type);
+ }
if (receiver != null) receiver.send(updatedCacheValue, null);
}
};
@@ -627,7 +649,7 @@
if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
receiver.send(cacheValue, null);
} else {
- ResultReceiver proxy = buildProxyReceiver(downstream, receiver);
+ ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
runUiTetherProvisioning(downstream, proxy);
}
}
diff --git a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
index fa7d3fc..ad04b7d 100644
--- a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
+++ b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
@@ -49,6 +49,9 @@
/**
* Gets the content capture options for the given user and package, or {@code null} if the
* package is not whitelisted by the service.
+ *
+ * <p><b>NOTE: </b>this method is called by the {@code ActivityManager} service and hence cannot
+ * hold the main service lock.
*/
@Nullable
public abstract ContentCaptureOptions getOptionsForPackage(@UserIdInt int userId,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 10f7db5..9e2fd4e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -74,7 +74,15 @@
@GuardedBy("mLock")
private boolean mSystemAudioControlFeatureEnabled;
- private boolean mTvSystemAudioModeSupport;
+ /**
+ * Indicates if the TV that the current device is connected to supports System Audio Mode or not
+ *
+ * <p>If the current device has no information on this, keep mTvSystemAudioModeSupport null
+ *
+ * <p>The boolean will be reset to null every time when the current device goes to standby
+ * or loses its physical address.
+ */
+ private Boolean mTvSystemAudioModeSupport = null;
// Whether ARC is available or not. "true" means that ARC is established between TV and
// AVR as audio receiver.
@@ -321,7 +329,7 @@
@ServiceThreadOnly
protected void onStandby(boolean initiatedByCec, int standbyAction) {
assertRunOnServiceThread();
- mTvSystemAudioModeSupport = false;
+ mTvSystemAudioModeSupport = null;
// Record the last state of System Audio Control before going to standby
synchronized (mLock) {
mService.writeStringSystemProperty(
@@ -961,7 +969,10 @@
@ServiceThreadOnly
void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
assertRunOnServiceThread();
- // TODO: validate port ID
+ if (!mService.isValidPortId(portId)) {
+ invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
+ return;
+ }
if (portId == getLocalActivePort()) {
invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
return;
@@ -1026,12 +1037,11 @@
* <p>The result of the query may be cached until Audio device type is put in standby or loses
* its physical address.
*/
- // TODO(amyjojo): making mTvSystemAudioModeSupport null originally and fix the logic.
void queryTvSystemAudioModeSupport(TvSystemAudioModeSupportedCallback callback) {
- if (!mTvSystemAudioModeSupport) {
+ if (mTvSystemAudioModeSupport == null) {
addAndStartAction(new DetectTvSystemAudioModeSupportAction(this, callback));
} else {
- callback.onResult(true);
+ callback.onResult(mTvSystemAudioModeSupport);
}
}
diff --git a/services/core/java/com/android/server/incident/IncidentCompanionService.java b/services/core/java/com/android/server/incident/IncidentCompanionService.java
index 55e054b..5c69c1d 100644
--- a/services/core/java/com/android/server/incident/IncidentCompanionService.java
+++ b/services/core/java/com/android/server/incident/IncidentCompanionService.java
@@ -300,7 +300,7 @@
android.Manifest.permission.DUMP, null);
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
- if (pkg == null) {
+ if (pkg != null) {
enforceCallerIsSameApp(pkg);
}
}
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index ed894ee..098b0e9 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -181,9 +181,8 @@
mServiceNameResolver = serviceNameResolver;
if (mServiceNameResolver != null) {
- mServiceNameResolver
- .setOnTemporaryServiceNameChangedCallback(
- (u, s) -> updateCachedServiceLocked(u));
+ mServiceNameResolver.setOnTemporaryServiceNameChangedCallback(
+ (u, s, t) -> onServiceNameChanged(u, s, t));
}
if (disallowProperty == null) {
@@ -582,6 +581,23 @@
}
/**
+ * Called when the service name changed (typically when using temporary services).
+ *
+ * <p>By default, it calls {@link #updateCachedServiceLocked(int)}; subclasses must either call
+ * that same method, or {@code super.onServiceNameChanged()}.
+ *
+ * @param userId user handle.
+ * @param serviceName the new service name.
+ * @param isTemporary whether the new service is temporary.
+ */
+ protected void onServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName,
+ boolean isTemporary) {
+ synchronized (mLock) {
+ updateCachedServiceLocked(userId);
+ }
+ }
+
+ /**
* Visits all services in the cache.
*/
@GuardedBy("mLock")
@@ -600,6 +616,23 @@
mServicesCache.clear();
}
+ /**
+ * Asserts that the given package name is owned by the UID making this call.
+ *
+ * @throws SecurityException when it's not...
+ */
+ protected final void assertCalledByPackageOwner(@NonNull String packageName) {
+ Preconditions.checkNotNull(packageName);
+ final int uid = Binder.getCallingUid();
+ final String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
+ if (packages != null) {
+ for (String candidate : packages) {
+ if (packageName.equals(candidate)) return; // Found it
+ }
+ }
+ throw new SecurityException("UID " + uid + " does not own " + packageName);
+ }
+
// TODO(b/117779333): support proto
protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
boolean realDebug = debug;
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index d204813..35d5956 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -155,7 +155,8 @@
}
mTemporaryServiceExpiration = SystemClock.elapsedRealtime() + durationMs;
mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs);
- notifyTemporaryServiceNameChangedLocked(userId, componentName);
+ notifyTemporaryServiceNameChangedLocked(userId, componentName,
+ /* isTemporary= */ true);
}
}
@@ -169,7 +170,8 @@
mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE);
mTemporaryHandler = null;
}
- notifyTemporaryServiceNameChangedLocked(userId, /* newTemporaryName= */ null);
+ notifyTemporaryServiceNameChangedLocked(userId, /* newTemporaryName= */ null,
+ /* isTemporary= */ false);
}
}
@@ -235,9 +237,9 @@
}
private void notifyTemporaryServiceNameChangedLocked(@UserIdInt int userId,
- @Nullable String newTemporaryName) {
+ @Nullable String newTemporaryName, boolean isTemporary) {
if (mOnSetCallback != null) {
- mOnSetCallback.onNameResolved(userId, newTemporaryName);
+ mOnSetCallback.onNameResolved(userId, newTemporaryName, isTemporary);
}
}
}
diff --git a/services/core/java/com/android/server/infra/ServiceNameResolver.java b/services/core/java/com/android/server/infra/ServiceNameResolver.java
index 8c348ebb..e20c459 100644
--- a/services/core/java/com/android/server/infra/ServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/ServiceNameResolver.java
@@ -39,7 +39,8 @@
/**
* The name change callback.
*/
- void onNameResolved(@UserIdInt int userId, @Nullable String serviceName);
+ void onNameResolved(@UserIdInt int userId, @Nullable String serviceName,
+ boolean isTemporary);
}
/**
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index 5a0b991..1820acf 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -769,6 +769,91 @@
mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs);
}
+ /**
+ * Returns the amount of time, in milliseconds, until the package would have reached its
+ * duration quota, assuming it has a job counting towards its quota the entire time. This takes
+ * into account any {@link TimingSession}s that may roll out of the window as the job is
+ * running.
+ */
+ @VisibleForTesting
+ long getTimeUntilQuotaConsumedLocked(final int userId, @NonNull final String packageName) {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ final int standbyBucket = JobSchedulerService.standbyBucketForPackage(
+ packageName, userId, nowElapsed);
+ if (standbyBucket == NEVER_INDEX) {
+ return 0;
+ }
+ List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
+ if (sessions == null || sessions.size() == 0) {
+ return mAllowedTimePerPeriodMs;
+ }
+
+ final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
+ final long startWindowElapsed = nowElapsed - stats.windowSizeMs;
+ final long startMaxElapsed = nowElapsed - MAX_PERIOD_MS;
+ final long allowedTimeRemainingMs = mAllowedTimePerPeriodMs - stats.executionTimeInWindowMs;
+ final long maxExecutionTimeRemainingMs =
+ mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs;
+
+ // Regular ACTIVE case. Since the bucket size equals the allowed time, the app jobs can
+ // essentially run until they reach the maximum limit.
+ if (stats.windowSizeMs == mAllowedTimePerPeriodMs) {
+ return calculateTimeUntilQuotaConsumedLocked(
+ sessions, startMaxElapsed, maxExecutionTimeRemainingMs);
+ }
+
+ // Need to check both max time and period time in case one is less than the other.
+ // For example, max time remaining could be less than bucket time remaining, but sessions
+ // contributing to the max time remaining could phase out enough that we'd want to use the
+ // bucket value.
+ return Math.min(
+ calculateTimeUntilQuotaConsumedLocked(
+ sessions, startMaxElapsed, maxExecutionTimeRemainingMs),
+ calculateTimeUntilQuotaConsumedLocked(
+ sessions, startWindowElapsed, allowedTimeRemainingMs));
+ }
+
+ /**
+ * Calculates how much time it will take, in milliseconds, until the quota is fully consumed.
+ *
+ * @param windowStartElapsed The start of the window, in the elapsed realtime timebase.
+ * @param deadSpaceMs How much time can be allowed to count towards the quota
+ */
+ private long calculateTimeUntilQuotaConsumedLocked(@NonNull List<TimingSession> sessions,
+ final long windowStartElapsed, long deadSpaceMs) {
+ long timeUntilQuotaConsumedMs = 0;
+ long start = windowStartElapsed;
+ for (int i = 0; i < sessions.size(); ++i) {
+ TimingSession session = sessions.get(i);
+
+ if (session.endTimeElapsed < windowStartElapsed) {
+ // Outside of window. Ignore.
+ continue;
+ } else if (session.startTimeElapsed <= windowStartElapsed) {
+ // Overlapping session. Can extend time by portion of session in window.
+ timeUntilQuotaConsumedMs += session.endTimeElapsed - windowStartElapsed;
+ start = session.endTimeElapsed;
+ } else {
+ // Completely within the window. Can only consider if there's enough dead space
+ // to get to the start of the session.
+ long diff = session.startTimeElapsed - start;
+ if (diff > deadSpaceMs) {
+ break;
+ }
+ timeUntilQuotaConsumedMs += diff
+ + (session.endTimeElapsed - session.startTimeElapsed);
+ deadSpaceMs -= diff;
+ start = session.endTimeElapsed;
+ }
+ }
+ // Will be non-zero if the loop didn't look at any sessions.
+ timeUntilQuotaConsumedMs += deadSpaceMs;
+ if (timeUntilQuotaConsumedMs > mMaxExecutionTimeMs) {
+ Slog.wtf(TAG, "Calculated quota consumed time too high: " + timeUntilQuotaConsumedMs);
+ }
+ return timeUntilQuotaConsumedMs;
+ }
+
/** Returns the execution stats of the app in the most recent window. */
@VisibleForTesting
@NonNull
@@ -1483,7 +1568,7 @@
return;
}
Message msg = mHandler.obtainMessage(MSG_REACHED_QUOTA, mPkg);
- final long timeRemainingMs = getRemainingExecutionTimeLocked(mPkg.userId,
+ final long timeRemainingMs = getTimeUntilQuotaConsumedLocked(mPkg.userId,
mPkg.packageName);
if (DEBUG) {
Slog.i(TAG, "Job for " + mPkg + " has " + timeRemainingMs + "ms left.");
@@ -1642,6 +1727,8 @@
// job is currently running.
// Reschedule message
Message rescheduleMsg = obtainMessage(MSG_REACHED_QUOTA, pkg);
+ timeRemainingMs = getTimeUntilQuotaConsumedLocked(pkg.userId,
+ pkg.packageName);
if (DEBUG) {
Slog.d(TAG, pkg + " has " + timeRemainingMs + "ms left.");
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 20b8987..54ec4f2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -84,6 +84,7 @@
import android.Manifest;
import android.Manifest.permission;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -107,6 +108,8 @@
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.backup.BackupManager;
+import android.app.role.OnRoleHoldersChangedListener;
+import android.app.role.RoleManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.ICompanionDeviceManager;
@@ -151,6 +154,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.DeviceConfig;
@@ -216,7 +220,6 @@
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.UserManagerService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -249,6 +252,7 @@
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
@@ -300,6 +304,12 @@
Adjustment.KEY_TEXT_REPLIES,
Adjustment.KEY_USER_SENTIMENT};
+ static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] {
+ RoleManager.ROLE_DIALER,
+ RoleManager.ROLE_SMS,
+ RoleManager.ROLE_EMERGENCY
+ };
+
// When #matchesCallFilter is called from the ringer, wait at most
// 3s to resolve the contacts. This timeout is required since
// ContactsProvider might take a long time to start up.
@@ -343,6 +353,8 @@
private IDeviceIdleController mDeviceIdleController;
private IUriGrantsManager mUgm;
private UriGrantsManagerInternal mUgmInternal;
+ private RoleObserver mRoleObserver;
+ private UserManager mUm;
final IBinder mForegroundToken = new Binder();
private WorkerHandler mHandler;
@@ -553,18 +565,13 @@
}
}
- UserManagerService getUserManagerService() {
- return UserManagerService.getInstance();
- }
-
void readPolicyXml(InputStream stream, boolean forRestore, int userId)
throws XmlPullParserException, NumberFormatException, IOException {
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
boolean migratedManagedServices = false;
- boolean ineligibleForManagedServices = forRestore
- && getUserManagerService().isManagedProfile(userId);
+ boolean ineligibleForManagedServices = forRestore && mUm.isManagedProfile(userId);
int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
@@ -612,7 +619,8 @@
mAssistants.resetDefaultAssistantsIfNecessary();
}
- private void loadPolicyFile() {
+ @VisibleForTesting
+ protected void loadPolicyFile() {
if (DBG) Slog.d(TAG, "loadPolicyFile");
synchronized (mPolicyFile) {
InputStream infile = null;
@@ -1530,7 +1538,8 @@
NotificationUsageStats usageStats, AtomicFile policyFile,
ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
- IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps) {
+ IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps,
+ UserManager userManager) {
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1552,6 +1561,7 @@
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
mDpm = dpm;
+ mUm = userManager;
mHandler = new WorkerHandler(looper);
mRankingThread.start();
@@ -1697,14 +1707,16 @@
AppGlobals.getPackageManager()),
new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
null, snoozeHelper, new NotificationUsageStats(getContext()),
- new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
+ new AtomicFile(new File(
+ systemDir, "notification_policy.xml"), "notification-policy"),
(ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
getGroupHelper(), ActivityManager.getService(),
LocalServices.getService(UsageStatsManagerInternal.class),
LocalServices.getService(DevicePolicyManagerInternal.class),
UriGrantsManager.getService(),
LocalServices.getService(UriGrantsManagerInternal.class),
- (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE));
+ (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE),
+ getContext().getSystemService(UserManager.class));
// register for various Intents
IntentFilter filter = new IntentFilter();
@@ -1827,6 +1839,9 @@
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mZenModeHelper.onSystemReady();
+ mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class),
+ getContext().getMainExecutor());
+ mRoleObserver.init();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
// bind to listener services.
@@ -4740,6 +4755,20 @@
}
}
+ /**
+ * Updates the flags for this notification to reflect whether it is a bubble or not.
+ */
+ private void flagNotificationForBubbles(NotificationRecord r, String pkg, int userId) {
+ Notification notification = r.getNotification();
+ boolean canBubble = mPreferencesHelper.areBubblesAllowed(pkg, userId)
+ && r.getChannel().canBubble();
+ if (notification.getBubbleMetadata() != null && canBubble) {
+ notification.flags |= Notification.FLAG_BUBBLE;
+ } else {
+ notification.flags &= ~Notification.FLAG_BUBBLE;
+ }
+ }
+
private void doChannelWarningToast(CharSequence toastText) {
Binder.withCleanCallingIdentity(() -> {
final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
@@ -5095,6 +5124,9 @@
final int id = n.getId();
final String tag = n.getTag();
+ // We need to fix the notification up a little for bubbles
+ flagNotificationForBubbles(r, pkg, callingUid);
+
// Handle grouped notifications and bail out early if we
// can to avoid extracting signals.
handleGroupedNotificationLocked(r, old, callingUid, callingPid);
@@ -8074,6 +8106,98 @@
}
}
+ class RoleObserver implements OnRoleHoldersChangedListener {
+ // Role name : user id : list of approved packages
+ private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps;
+
+ private final RoleManager mRm;
+ private final Executor mExecutor;
+
+ RoleObserver(@NonNull RoleManager roleManager,
+ @NonNull @CallbackExecutor Executor executor) {
+ mRm = roleManager;
+ mExecutor = executor;
+ }
+
+ public void init() {
+ List<UserInfo> users = mUm.getUsers();
+ mNonBlockableDefaultApps = new ArrayMap<>();
+ for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
+ final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>();
+ mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList);
+ for (int j = 0; j < users.size(); j++) {
+ Integer userId = users.get(j).getUserHandle().getIdentifier();
+ ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(
+ NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));
+ userToApprovedList.put(userId, approvedForUserId);
+ mPreferencesHelper.updateDefaultApps(userId, null, approvedForUserId);
+ }
+ }
+
+ mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
+ }
+
+ @VisibleForTesting
+ public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) {
+ return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg);
+ }
+
+ /**
+ * Convert the assistant-role holder into settings. The rest of the system uses the
+ * settings.
+ *
+ * @param roleName the name of the role whose holders are changed
+ * @param user the user for this role holder change
+ */
+ @Override
+ public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
+ // we only care about a couple of the roles they'll tell us about
+ boolean relevantChange = false;
+ for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
+ if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) {
+ relevantChange = true;
+ break;
+ }
+ }
+
+ if (!relevantChange) {
+ return;
+ }
+
+ ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user));
+
+ // find the diff
+ ArrayMap<Integer, ArraySet<String>> prevApprovedForRole =
+ mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>());
+ ArraySet<String> previouslyApproved =
+ prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>());
+
+ ArraySet<String> toRemove = new ArraySet<>();
+ ArraySet<String> toAdd = new ArraySet<>();
+
+ for (String previous : previouslyApproved) {
+ if (!roleHolders.contains(previous)) {
+ toRemove.add(previous);
+ }
+ }
+ for (String nowApproved : roleHolders) {
+ if (!previouslyApproved.contains(nowApproved)) {
+ toAdd.add(nowApproved);
+ }
+ }
+
+ // store newly approved apps
+ prevApprovedForRole.put(user.getIdentifier(), roleHolders);
+ mNonBlockableDefaultApps.put(roleName, prevApprovedForRole);
+
+ // update what apps can be blocked
+ mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd);
+
+ // RoleManager is the source of truth for this data so we don't need to trigger a
+ // write of the notification policy xml for this change
+ }
+ }
+
public static final class DumpFilter {
public boolean filtered = false;
public String pkgFilter;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index de93120..4cc08d8 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -783,7 +783,8 @@
// Consider Notification Assistant and system overrides to importance. If both, system wins.
if (!getChannel().hasUserSetImportance()
&& mAssistantImportance != IMPORTANCE_UNSPECIFIED
- && !getChannel().isImportanceLockedByOEM()) {
+ && !getChannel().isImportanceLockedByOEM()
+ && !getChannel().isImportanceLockedByCriticalDeviceFunction()) {
mImportance = mAssistantImportance;
mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_ASST;
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 660309c..a3e90dc 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -37,6 +37,8 @@
import android.service.notification.RankingHelperProto;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
@@ -100,6 +102,7 @@
private static final boolean DEFAULT_SHOW_BADGE = true;
private static final boolean DEFAULT_ALLOW_BUBBLE = true;
private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE = false;
+ private static final boolean DEFAULT_APP_LOCKED_IMPORTANCE = false;
/**
* Default value for what fields are user locked. See {@link LockableAppFields} for all lockable
@@ -659,6 +662,7 @@
channel.setImportanceLockedByOEM(true);
}
}
+ channel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance);
if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
channel.setLockscreenVisibility(
NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
@@ -707,6 +711,10 @@
if (updatedChannel.isImportanceLockedByOEM()) {
updatedChannel.setImportance(channel.getImportance());
}
+ updatedChannel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance);
+ if (updatedChannel.isImportanceLockedByCriticalDeviceFunction()) {
+ updatedChannel.setImportance(channel.getImportance());
+ }
r.channels.put(updatedChannel.getId(), updatedChannel);
@@ -844,6 +852,26 @@
}
}
+ public void updateDefaultApps(int userId, ArraySet<String> toRemove, ArraySet<String> toAdd) {
+ synchronized (mPackagePreferences) {
+ for (PackagePreferences p : mPackagePreferences.values()) {
+ if (userId == UserHandle.getUserId(p.uid)) {
+ if (toRemove != null && toRemove.contains(p.pkg)) {
+ p.defaultAppLockedImportance = false;
+ for (NotificationChannel channel : p.channels.values()) {
+ channel.setImportanceLockedByCriticalDeviceFunction(false);
+ }
+ } else if (toAdd != null && toAdd.contains(p.pkg)) {
+ p.defaultAppLockedImportance = true;
+ for (NotificationChannel channel : p.channels.values()) {
+ channel.setImportanceLockedByCriticalDeviceFunction(true);
+ }
+ }
+ }
+ }
+ }
+ }
+
public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg,
int uid, String groupId, boolean includeDeleted) {
Preconditions.checkNotNull(pkg);
@@ -1729,8 +1757,11 @@
boolean showBadge = DEFAULT_SHOW_BADGE;
boolean allowBubble = DEFAULT_ALLOW_BUBBLE;
int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
+ // these fields are loaded on boot from a different source of truth and so are not
+ // written to notification policy xml
boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
List<String> futureOemLockedChannels = new ArrayList<>();
+ boolean defaultAppLockedImportance = DEFAULT_APP_LOCKED_IMPORTANCE;
Delegate delegate = null;
ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 37dd63a..13ff873 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -422,8 +422,6 @@
final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
if (oi != null) {
mImpl.onOverlayPackageUpgrading(packageName, userId);
- } else {
- mImpl.onTargetPackageUpgrading(packageName, userId);
}
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 15ed063..a3d6380 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -22,7 +22,6 @@
import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
import static android.content.om.OverlayInfo.STATE_NO_IDMAP;
import static android.content.om.OverlayInfo.STATE_OVERLAY_UPGRADING;
-import static android.content.om.OverlayInfo.STATE_TARGET_UPGRADING;
import static com.android.server.om.OverlayManagerService.DEBUG;
import static com.android.server.om.OverlayManagerService.TAG;
@@ -30,12 +29,15 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
+import com.android.internal.util.ArrayUtils;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
@@ -54,8 +56,14 @@
* @see OverlayManagerService
*/
final class OverlayManagerServiceImpl {
- // Flags to use in conjunction with updateState.
+
+ /**
+ * @deprecated Not used. See {@link android.content.om.OverlayInfo#STATE_TARGET_UPGRADING}.
+ */
+ @Deprecated
private static final int FLAG_TARGET_IS_UPGRADING = 1 << 0;
+
+ // Flags to use in conjunction with updateState.
private static final int FLAG_OVERLAY_IS_UPGRADING = 1 << 1;
private final PackageManagerHelper mPackageManager;
@@ -247,9 +255,7 @@
Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId);
}
- if (updateAllOverlaysForTarget(packageName, userId, 0)) {
- mListener.onOverlaysChanged(packageName, userId);
- }
+ updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
@@ -257,16 +263,7 @@
Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
}
- updateAllOverlaysForTarget(packageName, userId, 0);
- }
-
- void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) {
- if (DEBUG) {
- Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId="
- + userId);
- }
-
- updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING);
+ updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
void onTargetPackageUpgraded(@NonNull final String packageName, final int userId) {
@@ -274,7 +271,7 @@
Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
}
- updateAllOverlaysForTarget(packageName, userId, 0);
+ updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
@@ -282,22 +279,27 @@
Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
}
- if (updateAllOverlaysForTarget(packageName, userId, 0)) {
- mListener.onOverlaysChanged(packageName, userId);
- }
+ updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
/**
* Update the state of any overlays for this target.
- *
- * Returns true if the system should refresh the app's overlay paths (i.e.
- * if the settings were modified for this target, or there is at least one
- * enabled framework overlay).
*/
- private boolean updateAllOverlaysForTarget(@NonNull final String targetPackageName,
+ private void updateAndRefreshOverlaysForTarget(@NonNull final String targetPackageName,
final int userId, final int flags) {
+ final List<OverlayInfo> ois = new ArrayList<>();
+
+ // Framework overlays added first because order matters when resolving a resource
+ if (!"android".equals(targetPackageName)) {
+ ois.addAll(mSettings.getOverlaysForTarget("android", userId));
+ }
+
+ // Then add the targeted, non-framework overlays which have higher priority
+ ois.addAll(mSettings.getOverlaysForTarget(targetPackageName, userId));
+
+ final List<String> enabledBaseCodePaths = new ArrayList<>(ois.size());
+
boolean modified = false;
- final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(targetPackageName, userId);
final int n = ois.size();
for (int i = 0; i < n; i++) {
final OverlayInfo oi = ois.get(i);
@@ -313,13 +315,35 @@
Slog.e(TAG, "failed to update settings", e);
modified |= mSettings.remove(oi.packageName, userId);
}
+
+ if (oi.isEnabled() && overlayPackage.applicationInfo != null) {
+ enabledBaseCodePaths.add(overlayPackage.applicationInfo.getBaseCodePath());
+ }
}
}
- // check for enabled framework overlays
- modified = modified || !getEnabledOverlayPackageNames("android", userId).isEmpty();
+ if (!modified) {
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, userId);
+ ApplicationInfo appInfo = packageInfo == null ? null : packageInfo.applicationInfo;
+ String[] resourceDirs = appInfo == null ? null : appInfo.resourceDirs;
- return modified;
+ // If the lists aren't the same length, the enabled overlays have changed
+ if (ArrayUtils.size(resourceDirs) != enabledBaseCodePaths.size()) {
+ modified = true;
+ } else if (resourceDirs != null) {
+ // If any element isn't equal, an overlay or the order of overlays has changed
+ for (int index = 0; index < resourceDirs.length; index++) {
+ if (!resourceDirs[index].equals(enabledBaseCodePaths.get(index))) {
+ modified = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (modified) {
+ mListener.onOverlaysChanged(targetPackageName, userId);
+ }
}
void onOverlayPackageAdded(@NonNull final String packageName, final int userId) {
@@ -670,10 +694,6 @@
@Nullable final PackageInfo overlayPackage, final int userId, final int flags)
throws OverlayManagerSettings.BadKeyException {
- if ((flags & FLAG_TARGET_IS_UPGRADING) != 0) {
- return STATE_TARGET_UPGRADING;
- }
-
if ((flags & FLAG_OVERLAY_IS_UPGRADING) != 0) {
return STATE_OVERLAY_UPGRADING;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index afa5ae9..ce3c452 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -396,6 +396,11 @@
} finally {
IoUtils.closeQuietly(fis);
}
+ // After all of the sessions were loaded, they are ready to be sealed and validated
+ for (int i = 0; i < mSessions.size(); ++i) {
+ PackageInstallerSession session = mSessions.valueAt(i);
+ session.sealAndValidateIfNecessary();
+ }
}
@GuardedBy("mSessions")
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index f1d4524..5d539a4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -231,6 +231,8 @@
@GuardedBy("mLock")
private boolean mSealed = false;
@GuardedBy("mLock")
+ private boolean mShouldBeSealed = false;
+ @GuardedBy("mLock")
private boolean mCommitted = false;
@GuardedBy("mLock")
private boolean mRelinquished = false;
@@ -430,6 +432,7 @@
this.updatedMillis = createdMillis;
this.stageDir = stageDir;
this.stageCid = stageCid;
+ this.mShouldBeSealed = sealed;
if (childSessionIds != null) {
for (int childSessionId : childSessionIds) {
mChildSessionIds.put(childSessionId, 0);
@@ -450,16 +453,6 @@
mStagedSessionErrorCode = stagedSessionErrorCode;
mStagedSessionErrorMessage =
stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
- if (sealed) {
- synchronized (mLock) {
- try {
- sealAndValidateLocked();
- } catch (PackageManagerException | IOException e) {
- destroyInternal();
- throw new IllegalArgumentException(e);
- }
- }
- }
}
public SessionInfo generateInfo() {
@@ -932,6 +925,8 @@
@NonNull IntentSender statusReceiver, boolean forTransfer) {
Preconditions.checkNotNull(statusReceiver);
+ List<PackageInstallerSession> childSessions = getChildSessions();
+
final boolean wasSealed;
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
@@ -963,7 +958,7 @@
wasSealed = mSealed;
if (!mSealed) {
try {
- sealAndValidateLocked();
+ sealAndValidateLocked(childSessions);
} catch (IOException e) {
throw new IllegalArgumentException(e);
} catch (PackageManagerException e) {
@@ -994,21 +989,91 @@
return true;
}
+ /** Return a list of child sessions or null if the session is not multipackage
+ *
+ * <p> This method is handy to prevent potential deadlocks (b/123391593)
+ */
+ private @Nullable List<PackageInstallerSession> getChildSessions() {
+ List<PackageInstallerSession> childSessions = null;
+ if (isMultiPackage()) {
+ final int[] childSessionIds = getChildSessionIds();
+ childSessions = new ArrayList<>(childSessionIds.length);
+ for (int childSessionId : childSessionIds) {
+ childSessions.add(mSessionProvider.getSession(childSessionId));
+ }
+ }
+ return childSessions;
+ }
+
+ /**
+ * Assert multipackage install has consistent sessions.
+ *
+ * @throws PackageManagerException if child sessions don't match parent session
+ * in respect to staged and enable rollback parameters.
+ */
+ @GuardedBy("mLock")
+ private void assertMultiPackageConsistencyLocked(
+ @NonNull List<PackageInstallerSession> childSessions) throws PackageManagerException {
+ for (PackageInstallerSession childSession : childSessions) {
+ // It might be that the parent session is loaded before all of it's child sessions are,
+ // e.g. when reading sessions from XML. Those sessions will be null here, and their
+ // conformance with the multipackage params will be checked when they're loaded.
+ if (childSession == null) {
+ continue;
+ }
+ assertConsistencyWithLocked(childSession);
+ }
+ }
+
+ /**
+ * Assert consistency with the given session.
+ *
+ * @throws PackageManagerException if other sessions doesn't match this session
+ * in respect to staged and enable rollback parameters.
+ */
+ @GuardedBy("mLock")
+ private void assertConsistencyWithLocked(PackageInstallerSession other)
+ throws PackageManagerException {
+ // Session groups must be consistent wrt to isStaged parameter. Non-staging session
+ // cannot be grouped with staging sessions.
+ if (this.params.isStaged != other.params.isStaged) {
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
+ "Multipackage Inconsistency: session " + other.sessionId
+ + " and session " + sessionId
+ + " have inconsistent staged settings");
+ }
+ if (this.params.getEnableRollback() != other.params.getEnableRollback()) {
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
+ "Multipackage Inconsistency: session " + other.sessionId
+ + " and session " + sessionId
+ + " have inconsistent rollback settings");
+ }
+ }
+
/**
* Seal the session to prevent further modification and validate the contents of it.
*
* <p>The session will be sealed after calling this method even if it failed.
*
+ * @param childSessions the child sessions of a multipackage that will be checked for
+ * consistency. Can be null if session is not multipackage.
* @throws PackageManagerException if the session was sealed but something went wrong. If the
* session was sealed this is the only possible exception.
*/
@GuardedBy("mLock")
- private void sealAndValidateLocked() throws PackageManagerException, IOException {
+ private void sealAndValidateLocked(List<PackageInstallerSession> childSessions)
+ throws PackageManagerException, IOException {
assertNoWriteFileTransfersOpenLocked();
assertPreparedAndNotDestroyedLocked("sealing of session");
mSealed = true;
+ if (childSessions != null) {
+ assertMultiPackageConsistencyLocked(childSessions);
+ }
+
if (params.isStaged) {
final PackageInstallerSession activeSession = mStagingManager.getActiveSession();
final boolean anotherSessionAlreadyInProgress =
@@ -1048,6 +1113,38 @@
}
}
+ /**
+ * If session should be sealed, then it's sealed to prevent further modification
+ * and then it's validated.
+ *
+ * If the session was sealed but something went wrong then it's destroyed.
+ *
+ * <p> This is meant to be called after all of the sessions are loaded and added to
+ * PackageInstallerService
+ */
+ void sealAndValidateIfNecessary() {
+ synchronized (mLock) {
+ if (!mShouldBeSealed) {
+ return;
+ }
+ }
+ List<PackageInstallerSession> childSessions = getChildSessions();
+ synchronized (mLock) {
+ try {
+ sealAndValidateLocked(childSessions);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "Package not valid", e);
+ // Session is sealed but could not be verified, we need to destroy it.
+ destroyInternal();
+ // Dispatch message to remove session from PackageInstallerService
+ dispatchSessionFinished(
+ e.error, ExceptionUtils.getCompleteMessage(e), null);
+ }
+ }
+ }
+
/** Update the timestamp of when the staged session last changed state */
public void markUpdated() {
synchronized (mLock) {
@@ -1076,12 +1173,14 @@
throw new SecurityException("Can only transfer sessions that use public options");
}
+ List<PackageInstallerSession> childSessions = getChildSessions();
+
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotSealedLocked("transfer");
try {
- sealAndValidateLocked();
+ sealAndValidateLocked(childSessions);
} catch (IOException e) {
throw new IllegalStateException(e);
} catch (PackageManagerException e) {
@@ -1132,14 +1231,7 @@
// outside of the lock, because reading the child
// sessions with the lock held could lead to deadlock
// (b/123391593).
- List<PackageInstallerSession> childSessions = null;
- if (isMultiPackage()) {
- final int[] childSessionIds = getChildSessionIds();
- childSessions = new ArrayList<>(childSessionIds.length);
- for (int childSessionId : childSessionIds) {
- childSessions.add(mSessionProvider.getSession(childSessionId));
- }
- }
+ List<PackageInstallerSession> childSessions = getChildSessions();
try {
synchronized (mLock) {
@@ -1965,15 +2057,6 @@
+ " does not exist"),
false, true).rethrowAsRuntimeException();
}
- // Session groups must be consistent wrt to isStaged parameter. Non-staging session
- // cannot be grouped with staging sessions.
- if (this.params.isStaged ^ childSession.params.isStaged) {
- throw new RemoteException("Unable to add child.",
- new PackageManagerException("Child session " + childSessionId
- + " and parent session " + this.sessionId + " do not have consistent"
- + " staging session settings."),
- false, true);
- }
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotSealedLocked("addChildSessionId");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6c1472c..3cab9e5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2971,7 +2971,7 @@
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
- updateAllSharedLibrariesLPw(null);
+ updateAllSharedLibrariesLocked(null, Collections.unmodifiableMap(mPackages));
for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
// NOTE: We ignore potential failures here during a system scan (like
@@ -10022,11 +10022,11 @@
}
@GuardedBy("mPackages")
- private void updateSharedLibrariesLPr(PackageParser.Package pkg,
- PackageParser.Package changingLib) throws PackageManagerException {
+ private void updateSharedLibrariesLocked(PackageParser.Package pkg,
+ PackageParser.Package changingLib, Map<String, PackageParser.Package> availablePackages)
+ throws PackageManagerException {
final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
- collectSharedLibraryInfos(pkg, Collections.unmodifiableMap(mPackages),
- mSharedLibraries, null);
+ collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null);
executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos);
}
@@ -10118,7 +10118,6 @@
+ " library " + libName + " version "
+ libraryInfo.getLongVersion() + "; failing!");
}
-
PackageParser.Package libPkg =
availablePackages.get(libraryInfo.getPackageName());
if (libPkg == null) {
@@ -10126,12 +10125,8 @@
"Package " + packageName + " requires unavailable static shared"
+ " library; failing!");
}
-
final String[] expectedCertDigests = requiredCertDigests[i];
-
-
if (expectedCertDigests.length > 1) {
-
// For apps targeting O MR1 we require explicit enumeration of all certs.
final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1)
? PackageUtils.computeSignaturesSha256Digests(
@@ -10163,7 +10158,6 @@
}
}
} else {
-
// lib signing cert could have rotated beyond the one expected, check to see
// if the new one has been blessed by the old
if (!libPkg.mSigningDetails.hasSha256Certificate(
@@ -10175,7 +10169,6 @@
}
}
}
-
if (outUsedLibraries == null) {
outUsedLibraries = new ArrayList<>();
}
@@ -10186,7 +10179,7 @@
}
private static boolean hasString(List<String> list, List<String> which) {
- if (list == null) {
+ if (list == null || which == null) {
return false;
}
for (int i=list.size()-1; i>=0; i--) {
@@ -10200,39 +10193,63 @@
}
@GuardedBy("mPackages")
- private ArrayList<PackageParser.Package> updateAllSharedLibrariesLPw(
- PackageParser.Package changingPkg) {
- ArrayList<PackageParser.Package> res = null;
- for (PackageParser.Package pkg : mPackages.values()) {
- if (changingPkg != null
- && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
- && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
- && !ArrayUtils.contains(pkg.usesStaticLibraries,
- changingPkg.staticSharedLibName)) {
- return null;
- }
- if (res == null) {
- res = new ArrayList<>();
- }
- res.add(pkg);
- try {
- updateSharedLibrariesLPr(pkg, changingPkg);
- } catch (PackageManagerException e) {
- // If a system app update or an app and a required lib missing we
- // delete the package and for updated system apps keep the data as
- // it is better for the user to reinstall than to be in an limbo
- // state. Also libs disappearing under an app should never happen
- // - just in case.
- if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
- final int flags = pkg.isUpdatedSystemApp()
- ? PackageManager.DELETE_KEEP_DATA : 0;
- deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
- flags , null, true, null);
- }
- Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
- }
+ private ArrayList<PackageParser.Package> updateAllSharedLibrariesLocked(
+ PackageParser.Package updatedPkg,
+ Map<String, PackageParser.Package> availablePackages) {
+ ArrayList<PackageParser.Package> resultList = null;
+ // Set of all descendants of a library; used to eliminate cycles
+ ArraySet<String> descendants = null;
+ // The current list of packages that need updating
+ ArrayList<PackageParser.Package> needsUpdating = null;
+ if (updatedPkg != null) {
+ needsUpdating = new ArrayList<>(1);
+ needsUpdating.add(updatedPkg);
}
- return res;
+ do {
+ final PackageParser.Package changingPkg =
+ (needsUpdating == null) ? null : needsUpdating.remove(0);
+ for (int i = mPackages.size() - 1; i >= 0; --i) {
+ final PackageParser.Package pkg = mPackages.valueAt(i);
+ if (changingPkg != null
+ && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
+ && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
+ && !ArrayUtils.contains(pkg.usesStaticLibraries,
+ changingPkg.staticSharedLibName)) {
+ continue;
+ }
+ if (resultList == null) {
+ resultList = new ArrayList<>();
+ }
+ resultList.add(pkg);
+ // if we're updating a shared library, all of its descendants must be updated
+ if (changingPkg != null) {
+ if (descendants == null) {
+ descendants = new ArraySet<>();
+ }
+ if (!descendants.contains(pkg.packageName)) {
+ descendants.add(pkg.packageName);
+ needsUpdating.add(pkg);
+ }
+ }
+ try {
+ updateSharedLibrariesLocked(pkg, changingPkg, availablePackages);
+ } catch (PackageManagerException e) {
+ // If a system app update or an app and a required lib missing we
+ // delete the package and for updated system apps keep the data as
+ // it is better for the user to reinstall than to be in an limbo
+ // state. Also libs disappearing under an app should never happen
+ // - just in case.
+ if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
+ final int flags = pkg.isUpdatedSystemApp()
+ ? PackageManager.DELETE_KEEP_DATA : 0;
+ deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
+ flags , null, true, null);
+ }
+ Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
+ }
+ }
+ } while (needsUpdating != null && needsUpdating.size() > 0);
+ return resultList;
}
@GuardedBy({"mInstallLock", "mPackages"})
@@ -11654,19 +11671,19 @@
for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
commitSharedLibraryInfoLocked(info);
}
+ final Map<String, PackageParser.Package> combinedPackages =
+ reconciledPkg.getCombinedPackages();
try {
// Shared libraries for the package need to be updated.
- updateSharedLibrariesLPr(pkg, null);
+ updateSharedLibrariesLocked(pkg, null, combinedPackages);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
}
- }
-
- if (reconciledPkg.hasDynamicSharedLibraries() && (scanFlags & SCAN_BOOTING) == 0) {
- // If we are not booting, we need to update any applications
- // that are clients of our shared library. If we are booting,
- // this will all be done once the scan is complete.
- clientLibPkgs = updateAllSharedLibrariesLPw(pkg);
+ // Update all applications that use this library. Skip when booting
+ // since this will be done after all packages are scaned.
+ if ((scanFlags & SCAN_BOOTING) == 0) {
+ clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages);
+ }
}
}
@@ -15755,6 +15772,7 @@
* TODO: move most of the data contained her into a PackageSetting for commit.
*/
private static class ReconciledPackage {
+ public final ReconcileRequest request;
public final PackageSetting pkgSetting;
public final ScanResult scanResult;
// TODO: Remove install-specific details from the reconcile result
@@ -15768,14 +15786,18 @@
public ArrayList<SharedLibraryInfo> collectedSharedLibraryInfos;
public final boolean removeAppKeySetData;
- private ReconciledPackage(InstallArgs installArgs, PackageSetting pkgSetting,
+ private ReconciledPackage(ReconcileRequest request,
+ InstallArgs installArgs,
+ PackageSetting pkgSetting,
PackageInstalledInfo installResult,
- PrepareResult prepareResult, ScanResult scanResult,
+ PrepareResult prepareResult,
+ ScanResult scanResult,
DeletePackageAction deletePackageAction,
List<SharedLibraryInfo> allowedSharedLibraryInfos,
SigningDetails signingDetails,
boolean sharedUserSignaturesChanged,
boolean removeAppKeySetData) {
+ this.request = request;
this.installArgs = installArgs;
this.pkgSetting = pkgSetting;
this.installResult = installResult;
@@ -15788,9 +15810,20 @@
this.removeAppKeySetData = removeAppKeySetData;
}
- public boolean hasDynamicSharedLibraries() {
- return !ArrayUtils.isEmpty(allowedSharedLibraryInfos)
- && allowedSharedLibraryInfos.get(0).getType() != SharedLibraryInfo.TYPE_STATIC;
+ /**
+ * Returns a combined set of packages containing the packages already installed combined
+ * with the package(s) currently being installed. The to-be installed packages take
+ * precedence and may shadow already installed packages.
+ */
+ private Map<String, PackageParser.Package> getCombinedPackages() {
+ final ArrayMap<String, PackageParser.Package> combinedPackages =
+ new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size());
+
+ combinedPackages.putAll(request.allPackages);
+ for (ScanResult scanResult : request.scannedPackages.values()) {
+ combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+ }
+ return combinedPackages;
}
}
@@ -15980,7 +16013,7 @@
}
result.put(installPackageName,
- new ReconciledPackage(installArgs, scanResult.pkgSetting,
+ new ReconciledPackage(request, installArgs, scanResult.pkgSetting,
res, request.preparedPackages.get(installPackageName), scanResult,
deletePackageAction, allowedSharedLibInfos, signingDetails,
sharedUserSignaturesChanged, removeAppKeySetData));
@@ -18415,7 +18448,7 @@
try {
// update shared libraries for the newly re-installed system package
- updateSharedLibrariesLPr(pkg, null);
+ updateSharedLibrariesLocked(pkg, null, Collections.unmodifiableMap(mPackages));
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
@@ -20239,6 +20272,11 @@
return mContext.getString(R.string.config_defaultTextClassifierPackage);
}
+ @Override
+ public String getAttentionServicePackageName() {
+ return mContext.getString(R.string.config_defaultAttentionService);
+ }
+
private @Nullable String getDocumenterPackageName() {
final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
@@ -20489,7 +20527,7 @@
prepareAppDataAfterInstallLIF(pkg);
synchronized (mPackages) {
try {
- updateSharedLibrariesLPr(pkg, null);
+ updateSharedLibrariesLocked(pkg, null, mPackages);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
}
@@ -23333,6 +23371,23 @@
}
return results;
}
+
+ @Override
+ public int getLocationFlags(String packageName) throws RemoteException {
+ int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ ApplicationInfo appInfo = getApplicationInfo(packageName,
+ /*flags*/ 0,
+ /*userId*/ callingUser);
+ if (appInfo == null) {
+ throw new RemoteException(
+ "Couldn't get ApplicationInfo for package " + packageName);
+ }
+ return ((appInfo.isSystemApp() ? IPackageManagerNative.LOCATION_SYSTEM : 0)
+ | (appInfo.isVendor() ? IPackageManagerNative.LOCATION_VENDOR : 0)
+ | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0)
+ | (appInfo.isProductServices()
+ ? IPackageManagerNative.LOCATION_PRODUCT_SERVICES : 0));
+ }
}
private class PackageManagerInternalImpl extends PackageManagerInternal {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 096335e..6a1f223 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4383,6 +4383,7 @@
ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION, "PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION",
ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE, "PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE",
ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE, "ALLOW_AUDIO_PLAYBACK_CAPTURE",
+ ApplicationInfo.PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX, "ALLOW_EXTERNAL_STORAGE_SANDBOX",
ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND, "BACKUP_IN_FOREGROUND",
ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE, "DEFAULT_TO_DEVICE_PROTECTED_STORAGE",
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 39c731c..190610c 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -44,11 +44,13 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.storage.IStorageManager;
import android.util.Slog;
import android.util.SparseArray;
import android.util.apk.ApkSignatureVerifier;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageHelper;
import com.android.internal.os.BackgroundThread;
import java.io.File;
@@ -253,6 +255,21 @@
}
}
+ // Make sure we start a filesystem checkpoint on the next boot.
+ try {
+ IStorageManager storageManager = PackageHelper.getStorageManager();
+ if (storageManager.supportsCheckpoint()) {
+ storageManager.startCheckpoint(1 /* numRetries */);
+ }
+ } catch (RemoteException e) {
+ // While StorageManager lives in the same process, the native implementation
+ // it calls through lives in 'vold'; so, this call can fail if 'vold' isn't
+ // reachable.
+ // Since we can live without filesystem checkpointing, just warn in this case
+ // and continue.
+ Slog.w(TAG, "Could not start filesystem checkpoint.");
+ }
+
session.setStagedSessionReady();
if (sessionContainsApex(session)
&& !mApexManager.markStagedSessionReady(session.sessionId)) {
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index e6e2c76..1833200 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -740,6 +740,14 @@
LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS);
}
+ // Atthention Service
+ String attentionServicePackageName =
+ mContext.getPackageManager().getAttentionServicePackageName();
+ if (!TextUtils.isEmpty(attentionServicePackageName)) {
+ grantPermissionsToSystemPackage(attentionServicePackageName, userId,
+ CAMERA_PERMISSIONS);
+ }
+
// There is no real "marker" interface to identify the shared storage backup, it is
// hardcoded in BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE.
grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7c87462..88109d3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -206,7 +206,6 @@
import com.android.internal.policy.PhoneWindow;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ScreenshotHelper;
import com.android.server.ExtconStateObserver;
import com.android.server.ExtconUEventObserver;
import com.android.server.GestureLauncherService;
@@ -377,7 +376,6 @@
BurnInProtectionHelper mBurnInProtectionHelper;
private DisplayFoldController mDisplayFoldController;
AppOpsManager mAppOpsManager;
- private ScreenshotHelper mScreenshotHelper;
private boolean mHasFeatureWatch;
private boolean mHasFeatureLeanback;
private boolean mHasFeatureHdmiCec;
@@ -1923,7 +1921,6 @@
mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged();
}
});
- mScreenshotHelper = new ScreenshotHelper(mContext);
}
/**
@@ -2226,6 +2223,11 @@
@Override
public boolean canBeHiddenByKeyguardLw(WindowState win) {
+
+ // Keyguard visibility of window from activities are determined over activity visibility.
+ if (win.getAppToken() != null) {
+ return false;
+ }
switch (win.getAttrs().type) {
case TYPE_STATUS_BAR:
case TYPE_NAVIGATION_BAR:
@@ -2239,19 +2241,30 @@
}
private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) {
+ final LayoutParams attrs = win.getAttrs();
- // Keyguard visibility of window from activities are determined over activity visibility.
- if (win.getAppToken() != null) {
- return false;
+ boolean hideDockDivider = attrs.type == TYPE_DOCK_DIVIDER
+ && !mWindowManagerInternal.isStackVisibleLw(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ if (hideDockDivider) {
+ return true;
}
- final LayoutParams attrs = win.getAttrs();
+ // If AOD is showing, the IME should be hidden. However, sometimes the AOD is considered
+ // hidden because it's in the process of hiding, but it's still being shown on screen.
+ // In that case, we want to continue hiding the IME until the windows have completed
+ // drawing. This way, we know that the IME can be safely shown since the other windows are
+ // now shown.
+ final boolean hideIme = win.isInputMethodWindow()
+ && (mAodShowing || !mDefaultDisplayPolicy.isWindowManagerDrawComplete());
+ if (hideIme) {
+ return true;
+ }
+
final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleLw()
&& (imeTarget.canShowWhenLocked() || !canBeHiddenByKeyguardLw(imeTarget));
// Show IME over the keyguard if the target allows it
- boolean allowWhenLocked = (win.isInputMethodWindow() || imeTarget == this)
- && showImeOverKeyguard;
+ boolean allowWhenLocked = win.isInputMethodWindow() && showImeOverKeyguard;
final boolean isKeyguardShowing = mKeyguardDelegate.isShowing();
@@ -2262,17 +2275,7 @@
|| (attrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
}
- boolean hideDockDivider = attrs.type == TYPE_DOCK_DIVIDER
- && !mWindowManagerInternal.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- // If AOD is showing, the IME should be hidden. However, sometimes the AOD is considered
- // hidden because it's in the process of hiding, but it's still being shown on screen.
- // In that case, we want to continue hiding the IME until the windows have completed
- // drawing. This way, we know that the IME can be safely shown since the other windows are
- // now shown.
- final boolean hideIme = win.isInputMethodWindow()
- && (mAodShowing || !mDefaultDisplayPolicy.isWindowManagerDrawComplete());
- return (isKeyguardShowing && !allowWhenLocked && win.getDisplayId() == DEFAULT_DISPLAY)
- || hideDockDivider || hideIme;
+ return isKeyguardShowing && !allowWhenLocked && win.getDisplayId() == DEFAULT_DISPLAY;
}
/** {@inheritDoc} */
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index f23b68e..38bdc62 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -594,7 +594,7 @@
boolean forceBackgroundCheck,
int locationMode) {
- this.adjustBrightnessFactor = adjustBrightnessFactor;
+ this.adjustBrightnessFactor = Math.min(1, Math.max(0, adjustBrightnessFactor));
this.advertiseIsEnabled = advertiseIsEnabled;
this.deferFullBackup = deferFullBackup;
this.deferKeyValueBackup = deferKeyValueBackup;
@@ -613,7 +613,14 @@
this.filesForNoninteractive = filesForNoninteractive;
this.forceAllAppsStandby = forceAllAppsStandby;
this.forceBackgroundCheck = forceBackgroundCheck;
- this.locationMode = locationMode;
+
+ if (locationMode < PowerManager.MIN_LOCATION_MODE
+ || PowerManager.MAX_LOCATION_MODE < locationMode) {
+ Slog.e(TAG, "Invalid location mode: " + locationMode);
+ this.locationMode = PowerManager.LOCATION_MODE_NO_CHANGE;
+ } else {
+ this.locationMode = locationMode;
+ }
mHashCode = Objects.hash(
adjustBrightnessFactor,
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index a5d291f..5f00148 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -425,9 +425,12 @@
if (packageName == null) return;
try {
- final int uid = context.getPackageManager()
+ final int packageUid = context.getPackageManager()
.getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
- Preconditions.checkArgument(Binder.getCallingUid() == uid);
+ final int callingUid = Binder.getCallingUid();
+ Preconditions.checkArgument(callingUid == packageUid
+ // Trust the system process:
+ || callingUid == android.os.Process.SYSTEM_UID);
} catch (Exception e) {
throw new RemoteException(
String.format("Invalid package: name=%s, error=%s", packageName, e));
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 0c9f815..c2a4339 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1719,6 +1719,7 @@
final WallpaperData systemWallpaper =
getWallpaperSafeLocked(userId, FLAG_SYSTEM);
switchWallpaper(systemWallpaper, null);
+ notifyCallbacksLocked(systemWallpaper);
}
// Make sure that the SELinux labeling of all the relevant files is correct.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5bbabfc..a93bdba 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1102,7 +1102,7 @@
ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this)
* 1000000L, fullscreen,
(info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, appInfo.targetSdkVersion,
- info.screenOrientation, mRotationAnimationHint, info.configChanges,
+ info.screenOrientation, mRotationAnimationHint,
mLaunchTaskBehind, isAlwaysFocusable());
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) {
Slog.v(TAG, "addAppToken: "
@@ -1151,11 +1151,11 @@
AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
- int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
+ int rotationAnimationHint, boolean launchTaskBehind,
boolean alwaysFocusable) {
return new AppWindowToken(service, token, mActivityComponent, voiceInteraction, dc,
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
- rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
+ rotationAnimationHint, launchTaskBehind, alwaysFocusable,
this);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index ea1db40..20586db 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -114,6 +114,7 @@
import android.os.UserManager;
import android.service.voice.IVoiceInteractionSession;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.EventLog;
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
@@ -1001,6 +1002,10 @@
if (callerApp.hasActivityInVisibleTask()) {
return false;
}
+ // don't abort if the caller is bound by a UID that's currently foreground
+ if (isBoundByForegroundUid(callerApp)) {
+ return false;
+ }
}
// don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
@@ -1015,6 +1020,11 @@
if (mService.isDeviceOwner(callingPackage)) {
return false;
}
+ // don't abort if the callingPackage has companion device
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ if (mService.isAssociatedCompanionApp(callingUserId, callingPackage)) {
+ return false;
+ }
// don't abort if the callingPackage is temporarily whitelisted
if (mService.isPackageNameWhitelistedForBgActivityStarts(callingPackage)) {
Slog.w(TAG, "Background activity start for " + callingPackage
@@ -1045,6 +1055,18 @@
return true;
}
+ private boolean isBoundByForegroundUid(WindowProcessController callerApp) {
+ final ArraySet<Integer> boundClientUids = callerApp.getBoundClientUids();
+ for (int i = boundClientUids.size() - 1; i >= 0; --i) {
+ final int uid = boundClientUids.valueAt(i);
+ if (mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid)
+ || mService.getUidState(uid) == ActivityManager.PROCESS_STATE_TOP) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Creates a launch intent for the given auxiliary resolution data.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index fc7646f..b2e5b6a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -510,4 +510,7 @@
* Called by DevicePolicyManagerService to set the package name of the device owner.
*/
public abstract void setDeviceOwnerPackageName(String deviceOwnerPkg);
+
+ /** Set all associated companion app that belongs to an userId. */
+ public abstract void setCompanionAppPackages(int userId, Set<String> companionAppPackages);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index faa98fa..9a8824f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -443,6 +443,9 @@
// VoiceInteractionManagerService
ComponentName mActiveVoiceInteractionServiceComponent;
+ // A map userId and all its companion app packages
+ private final Map<Integer, Set<String>> mCompanionAppPackageMap = new ArrayMap<>();
+
VrController mVrController;
KeyguardController mKeyguardController;
private final ClientLifecycleManager mLifecycleManager;
@@ -5909,6 +5912,14 @@
}
}
+ boolean isAssociatedCompanionApp(int userId, String packageName) {
+ final Set<String> allPackages = mCompanionAppPackageMap.get(userId);
+ if (allPackages == null) {
+ return false;
+ }
+ return allPackages.contains(packageName);
+ }
+
final class H extends Handler {
static final int REPORT_TIME_TRACKER_MSG = 1;
@@ -7282,5 +7293,17 @@
ActivityTaskManagerService.this.setDeviceOwnerPackageName(deviceOwnerPkg);
}
}
+
+ @Override
+ public void setCompanionAppPackages(int userId, Set<String> companionAppPackages) {
+ // Deep copy all content to make sure we do not rely on the source
+ final Set<String> result = new HashSet<>();
+ for (String pkg : companionAppPackages) {
+ result.add(pkg);
+ }
+ synchronized (mGlobalLock) {
+ mCompanionAppPackageMap.put(userId, result);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index c1b9bba..a53f85d 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -153,7 +153,6 @@
/** @see WindowContainer#fillsParent() */
private boolean mFillsParent;
- boolean layoutConfigChanges;
boolean mShowForAllUsers;
int mTargetSdk;
@@ -337,7 +336,7 @@
AppWindowToken(WindowManagerService service, IApplicationToken token,
ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
- int targetSdk, int orientation, int rotationAnimationHint, int configChanges,
+ int targetSdk, int orientation, int rotationAnimationHint,
boolean launchTaskBehind, boolean alwaysFocusable,
ActivityRecord activityRecord) {
this(service, token, activityComponent, voiceInteraction, dc, fullscreen);
@@ -348,7 +347,6 @@
mShowForAllUsers = showForAllUsers;
mTargetSdk = targetSdk;
mOrientation = orientation;
- layoutConfigChanges = (configChanges & (CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION)) != 0;
mLaunchTaskBehind = launchTaskBehind;
mAlwaysFocusable = alwaysFocusable;
mRotationAnimationHint = rotationAnimationHint;
@@ -1976,7 +1974,7 @@
final boolean surfaceReady = w.isDrawnLw() // Regular case
|| w.mWinAnimator.mSurfaceDestroyDeferred // The preserved surface is still ready.
|| w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface.
- final boolean needsLetterbox = w.isLetterboxedAppWindow() && fillsParent() && surfaceReady;
+ final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent();
if (needsLetterbox) {
if (mLetterbox == null) {
mLetterbox = new Letterbox(() -> makeChildSurface(null));
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 9bc8462..3bbe28d 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -173,8 +173,9 @@
}
final boolean wasVis = mWin.isVisibleLw();
final boolean wasAnim = mWin.isAnimatingLw();
- final boolean change = show ? mWin.showLw(!mNoAnimationOnNextShow && !skipAnimation())
- : mWin.hideLw(!mNoAnimationOnNextShow && !skipAnimation());
+ final boolean skipAnim = skipAnimation();
+ final boolean change = show ? mWin.showLw(!mNoAnimationOnNextShow && !skipAnim)
+ : mWin.hideLw(!mNoAnimationOnNextShow && !skipAnim);
mNoAnimationOnNextShow = false;
final int state = computeStateLw(wasVis, wasAnim, mWin, change);
final boolean stateChanged = updateStateLw(state);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0c34e25..77055c1 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -28,6 +28,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
@@ -655,7 +656,7 @@
if (DEBUG_LAYOUT && !w.mLayoutAttached) {
Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame
+ " mLayoutAttached=" + w.mLayoutAttached
- + " screen changed=" + w.isConfigChanged());
+ + " config reported=" + w.isLastConfigReportedToClient());
final AppWindowToken atoken = w.mAppToken;
if (gone) Slog.v(TAG, " GONE: mViewVisibility=" + w.mViewVisibility
+ " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.isHidden()
@@ -670,42 +671,34 @@
// If this view is GONE, then skip it -- keep the current frame, and let the caller know
// so they can ignore it if they want. (We do the normal layout for INVISIBLE windows,
// since that means "perform layout as normal, just don't display").
- if (!gone || !w.mHaveFrame || w.mLayoutNeeded
- || ((w.isConfigChanged() || w.setReportResizeHints())
- && !w.isGoneForLayoutLw() &&
- ((w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
- (w.mHasSurface && w.mAppToken != null &&
- w.mAppToken.layoutConfigChanges)))) {
- if (!w.mLayoutAttached) {
- if (mTmpInitial) {
- //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
- w.resetContentChanged();
- }
- if (w.mAttrs.type == TYPE_DREAM) {
- // Don't layout windows behind a dream, so that if it does stuff like hide
- // the status bar we won't get a bad transition when it goes away.
- mTmpWindow = w;
- }
- w.mLayoutNeeded = false;
- w.prelayout();
- final boolean firstLayout = !w.isLaidOut();
- getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);
- w.mLayoutSeq = mLayoutSeq;
-
- // If this is the first layout, we need to initialize the last inset values as
- // otherwise we'd immediately cause an unnecessary resize.
- if (firstLayout) {
- w.updateLastInsetValues();
- }
-
- if (w.mAppToken != null) {
- w.mAppToken.layoutLetterbox(w);
- }
-
- if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrameLw()
- + " mContainingFrame=" + w.getContainingFrame()
- + " mDisplayFrame=" + w.getDisplayFrameLw());
+ if ((!gone || !w.mHaveFrame || w.mLayoutNeeded) && !w.mLayoutAttached) {
+ if (mTmpInitial) {
+ w.resetContentChanged();
}
+ if (w.mAttrs.type == TYPE_DREAM) {
+ // Don't layout windows behind a dream, so that if it does stuff like hide
+ // the status bar we won't get a bad transition when it goes away.
+ mTmpWindow = w;
+ }
+ w.mLayoutNeeded = false;
+ w.prelayout();
+ final boolean firstLayout = !w.isLaidOut();
+ getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);
+ w.mLayoutSeq = mLayoutSeq;
+
+ // If this is the first layout, we need to initialize the last inset values as
+ // otherwise we'd immediately cause an unnecessary resize.
+ if (firstLayout) {
+ w.updateLastInsetValues();
+ }
+
+ if (w.mAppToken != null) {
+ w.mAppToken.layoutLetterbox(w);
+ }
+
+ if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrameLw()
+ + " mContainingFrame=" + w.getContainingFrame()
+ + " mDisplayFrame=" + w.getDisplayFrameLw());
}
};
@@ -3094,7 +3087,7 @@
/** Updates the layer assignment of windows on this display. */
void assignWindowLayers(boolean setLayoutNeeded) {
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "assignWindowLayers");
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "assignWindowLayers");
assignChildLayers(getPendingTransaction());
if (setLayoutNeeded) {
setLayoutNeeded();
@@ -3105,7 +3098,7 @@
// prepareSurfaces. This allows us to synchronize Z-ordering changes with
// the hiding and showing of surfaces.
scheduleAnimation();
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
// TODO: This should probably be called any time a visual change is made to the hierarchy like
@@ -3659,9 +3652,14 @@
// FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think it is animating.
pendingLayoutChanges = 0;
- mDisplayPolicy.beginPostLayoutPolicyLw();
- forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
- pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
+ try {
+ mDisplayPolicy.beginPostLayoutPolicyLw();
+ forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
+ pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
"after finishPostLayoutPolicyLw", pendingLayoutChanges);
mInsetsStateController.onPostLayout();
@@ -3670,7 +3668,13 @@
mTmpApplySurfaceChangesTransactionState.reset();
mTmpRecoveringMemory = recoveringMemory;
- forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
+
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");
+ try {
+ forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
prepareSurfaces();
mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
@@ -3720,11 +3724,6 @@
out.set(left, top, left + width, top + height);
}
- @Override
- public void getBounds(Rect out) {
- calculateBounds(mDisplayInfo, out);
- }
-
private void getBounds(Rect out, int orientation) {
getBounds(out);
@@ -3746,6 +3745,15 @@
}
void performLayout(boolean initial, boolean updateInputWindows) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performLayout");
+ try {
+ performLayoutNoTrace(initial, updateInputWindows);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+ }
+
+ private void performLayoutNoTrace(boolean initial, boolean updateInputWindows) {
if (!isLayoutNeeded()) {
return;
}
@@ -3755,13 +3763,14 @@
final int dh = mDisplayInfo.logicalHeight;
if (DEBUG_LAYOUT) {
Slog.v(TAG, "-------------------------------------");
- Slog.v(TAG, "performLayout: needed=" + isLayoutNeeded() + " dw=" + dw + " dh=" + dh);
+ Slog.v(TAG, "performLayout: needed=" + isLayoutNeeded() + " dw=" + dw
+ + " dh=" + dh);
}
mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
- // TODO: Not sure if we really need to set the rotation here since we are updating from the
- // display info above...
+ // TODO: Not sure if we really need to set the rotation here since we are updating from
+ // the display info above...
mDisplayFrames.mRotation = mRotation;
mDisplayPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode);
@@ -4801,20 +4810,25 @@
@Override
void prepareSurfaces() {
- final ScreenRotationAnimation screenRotationAnimation =
- mWmService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
- if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
- screenRotationAnimation.getEnterTransformation().getMatrix().getValues(mTmpFloats);
- mPendingTransaction.setMatrix(mWindowingLayer,
- mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
- mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
- mPendingTransaction.setPosition(mWindowingLayer,
- mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
- mPendingTransaction.setAlpha(mWindowingLayer,
- screenRotationAnimation.getEnterTransformation().getAlpha());
- }
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
+ try {
+ final ScreenRotationAnimation screenRotationAnimation =
+ mWmService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
+ if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
+ screenRotationAnimation.getEnterTransformation().getMatrix().getValues(mTmpFloats);
+ mPendingTransaction.setMatrix(mWindowingLayer,
+ mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
+ mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
+ mPendingTransaction.setPosition(mWindowingLayer,
+ mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
+ mPendingTransaction.setAlpha(mWindowingLayer,
+ screenRotationAnimation.getEnterTransformation().getAlpha());
+ }
- super.prepareSurfaces();
+ super.prepareSurfaces();
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
}
void assignStackOrdering() {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 5d38a69..1888e94 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -103,13 +103,16 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.localLOGV;
+import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Px;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PixelFormat;
@@ -255,6 +258,9 @@
private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
+ /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
+ @Px private int mWindowOutsetBottom;
+
private final StatusBarController mStatusBarController = new StatusBarController();
private final BarController mNavigationBarController = new BarController("NavigationBar",
@@ -731,6 +737,11 @@
return true;
}
+ private boolean hasStatusBarServicePermission(int pid, int uid) {
+ return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
/**
* Sanitize the layout parameters coming from a client. Allows the policy
* to do things like ensure that windows of a specific type can't take
@@ -740,7 +751,7 @@
* are modified in-place.
*/
public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
- boolean hasStatusBarServicePermission) {
+ int callingPid, int callingUid) {
final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
if (mScreenDecorWindows.contains(win)) {
@@ -748,7 +759,7 @@
// No longer has the flag set, so remove from the set.
mScreenDecorWindows.remove(win);
}
- } else if (isScreenDecor && hasStatusBarServicePermission) {
+ } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
mScreenDecorWindows.add(win);
}
@@ -1159,7 +1170,7 @@
final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
if (useOutsets) {
- int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
+ int outset = mWindowOutsetBottom;
if (outset > 0) {
if (displayRotation == Surface.ROTATION_0) {
outOutsets.bottom += outset;
@@ -1479,12 +1490,13 @@
}
// apply any navigation bar insets
sTmpRect.setEmpty();
- mStatusBar.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
+ final WindowFrames windowFrames = mStatusBar.getWindowFrames();
+ windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
displayFrames.mUnrestricted /* displayFrame */,
displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
- mStatusBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+ windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
// Let the status bar determine its size.
mStatusBar.computeFrameLw();
@@ -1524,8 +1536,9 @@
"dock=%s content=%s cur=%s", dockFrame.toString(),
displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
- if (!mStatusBar.isAnimatingLw() && !statusBarTranslucent
- && !mStatusBarController.wasRecentlyTranslucent()) {
+ if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
+ && !mStatusBar.isAnimatingLw()) {
+
// If the opaque status bar is currently requested to be visible, and not in the
// process of animating on or off, then we can tell the app that it is covered by
// it.
@@ -2180,7 +2193,7 @@
final Rect osf = windowFrames.mOutsetFrame;
osf.set(cf.left, cf.top, cf.right, cf.bottom);
windowFrames.setHasOutsets(true);
- int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
+ int outset = mWindowOutsetBottom;
if (outset > 0) {
int rotation = displayFrames.mRotation;
if (rotation == Surface.ROTATION_0) {
@@ -2336,7 +2349,7 @@
}
// Voice interaction overrides both top fullscreen and top docked.
- if (affectsSystemUi && win.getAttrs().type == TYPE_VOICE_INTERACTION) {
+ if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) {
if (mTopFullscreenOpaqueWindowState == null) {
mTopFullscreenOpaqueWindowState = win;
if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
@@ -2599,6 +2612,7 @@
// EXPERIMENT END
updateConfigurationAndScreenSizeDependentBehaviors();
+ mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
}
void updateConfigurationAndScreenSizeDependentBehaviors() {
@@ -2962,6 +2976,8 @@
mLastDockedStackSysUiFlags = dockedVisibility;
mLastFocusNeedsMenu = needsMenu;
mFocusedApp = win.getAppToken();
+ mLastNonDockedStackBounds.set(mNonDockedStackBounds);
+ mLastDockedStackBounds.set(mDockedStackBounds);
final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
final Rect dockedStackBounds = new Rect(mDockedStackBounds);
mHandler.post(() -> {
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index ab95e4b..8dae016 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
@@ -43,6 +44,9 @@
final SurfaceControl mInputSurface;
Rect mTmpClipRect = new Rect();
+ private final Rect mTmpRect = new Rect();
+ private final Point mOldPosition = new Point();
+ private final Rect mOldWindowCrop = new Rect();
InputConsumerImpl(WindowManagerService service, IBinder token, String name,
InputChannel inputChannel, int clientPid, UserHandle clientUser, int displayId) {
@@ -112,16 +116,22 @@
}
void layout(SurfaceControl.Transaction t, int dw, int dh) {
- t.setPosition(mInputSurface, 0, 0);
-
- mTmpClipRect.set(0, 0, dw, dh);
- t.setWindowCrop(mInputSurface, mTmpClipRect);
+ mTmpRect.set(0, 0, dw, dh);
+ layout(t, mTmpRect);
}
void layout(SurfaceControl.Transaction t, Rect r) {
- t.setPosition(mInputSurface, r.left, r.top);
mTmpClipRect.set(0, 0, r.width(), r.height());
+
+ if (mOldPosition.equals(r.left, r.top) && mOldWindowCrop.equals(mTmpClipRect)) {
+ return;
+ }
+
+ t.setPosition(mInputSurface, r.left, r.top);
t.setWindowCrop(mInputSurface, mTmpClipRect);
+
+ mOldPosition.set(r.left, r.top);
+ mOldWindowCrop.set(mTmpClipRect);
}
void hide(SurfaceControl.Transaction t) {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 5669451..835b9b1 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
@@ -190,8 +191,13 @@
}
void layoutInputConsumers(int dw, int dh) {
- for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
- mInputConsumers.valueAt(i).layout(mInputTransaction, dw, dh);
+ try {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "layoutInputConsumer");
+ for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
+ mInputConsumers.valueAt(i).layout(mInputTransaction, dw, dh);
+ }
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
@@ -401,7 +407,7 @@
final InputWindowHandle mInvalidInputWindow = new InputWindowHandle(null, null, mDisplayId);
private void updateInputWindows(boolean inDrag) {
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION);
pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP);
@@ -429,7 +435,7 @@
mDisplayContent.scheduleAnimation();
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@Override
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ed5f665..1ca31f1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
@@ -65,6 +66,7 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.EventLog;
@@ -551,18 +553,26 @@
return leakedSurface || killedApps;
}
+ void performSurfacePlacement(boolean recoveringMemory) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
+ try {
+ performSurfacePlacementNoTrace(recoveringMemory);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+ }
+
// "Something has changed! Let's make it correct now."
// TODO: Super crazy long method that should be broken down...
- void performSurfacePlacement(boolean recoveringMemory) {
+ void performSurfacePlacementNoTrace(boolean recoveringMemory) {
if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
+ Debug.getCallers(3));
int i;
- boolean updateInputWindowsNeeded = false;
if (mWmService.mFocusMayChange) {
mWmService.mFocusMayChange = false;
- updateInputWindowsNeeded = mWmService.updateFocusedWindowLocked(
+ mWmService.updateFocusedWindowLocked(
UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
}
@@ -586,6 +596,7 @@
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
mWmService.openSurfaceTransaction();
try {
applySurfaceChangesTransaction(recoveringMemory);
@@ -593,6 +604,7 @@
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
}
@@ -621,10 +633,8 @@
if (mWmService.mFocusMayChange) {
mWmService.mFocusMayChange = false;
- if (mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
- false /*updateInputWindows*/)) {
- updateInputWindowsNeeded = true;
- }
+ mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
+ false /*updateInputWindows*/);
}
if (isLayoutNeeded()) {
@@ -679,12 +689,6 @@
}
}
- // Finally update all input windows now that the window changes have stabilized.
- forAllDisplays(dc -> {
- dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
- dc.updateSystemGestureExclusion();
- });
-
mWmService.setHoldScreenLocked(mHoldScreen);
if (!mWmService.mDisplayFrozen) {
final int brightness = mScreenBrightness < 0 || mScreenBrightness > 1.0f
@@ -710,7 +714,7 @@
if (mWmService.mWaitingForDrawnCallback != null
|| (mOrientationChangeComplete && !isLayoutNeeded()
- && !mUpdateRotation)) {
+ && !mUpdateRotation)) {
mWmService.checkDrawnWindowsLocked();
}
@@ -742,12 +746,11 @@
mChildren.get(displayNdx).checkCompleteDeferredRemoval();
}
- if (updateInputWindowsNeeded) {
- forAllDisplays(dc -> {
- dc.getInputMonitor().updateInputWindowsLw(false /*force*/);
- });
- }
- forAllDisplays(DisplayContent::updateTouchExcludeRegion);
+ forAllDisplays(dc -> {
+ dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
+ dc.updateSystemGestureExclusion();
+ dc.updateTouchExcludeRegion();
+ });
// Check to see if we are now in a state where the screen should
// be enabled, because the window obscured flags have changed.
@@ -776,7 +779,7 @@
}
}
- if (!curDisplay.isAppAnimating() && curDisplay.mAppTransition.isRunning()) {
+ if (curDisplay.mAppTransition.isRunning() && !curDisplay.isAppAnimating()) {
// We have finished the animation of an app transition. To do this, we have
// delayed a lot of operations like showing and hiding apps, moving apps in
// Z-order, etc.
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 9b634f9..22b030d 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -426,11 +426,10 @@
}
@Override
- public void updateTapExcludeRegion(IWindow window, int regionId, int left, int top, int width,
- int height) {
+ public void updateTapExcludeRegion(IWindow window, int regionId, Region region) {
final long identity = Binder.clearCallingIdentity();
try {
- mService.updateTapExcludeRegion(window, regionId, left, top, width, height);
+ mService.updateTapExcludeRegion(window, regionId, region);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 35b8641..67686a5 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -82,6 +82,11 @@
return;
}
final Runnable resetAndInvokeFinish = () -> {
+ // We need to check again if the animation has been replaced with a new
+ // animation because the animatable may defer to finish.
+ if (anim != mAnimation) {
+ return;
+ }
reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
if (animationFinishedCallback != null) {
animationFinishedCallback.run();
diff --git a/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java b/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
index 0a4ab67..22f529b 100644
--- a/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
+++ b/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
@@ -21,38 +21,35 @@
import android.util.SparseArray;
/**
- * A holder that contains a collection of rectangular areas identified by int id. Each individual
- * region can be updated separately.
+ * A holder that contains a collection of regions identified by int id. Each individual region can
+ * be updated separately.
*/
class TapExcludeRegionHolder {
- private SparseArray<Rect> mTapExcludeRects = new SparseArray<>();
+ private SparseArray<Region> mTapExcludeRegions = new SparseArray<>();
/** Update the specified region with provided position and size. */
- void updateRegion(int regionId, int left, int top, int width, int height) {
- if (width <= 0 || height <= 0) {
- // A region became empty - remove it.
- mTapExcludeRects.remove(regionId);
+ void updateRegion(int regionId, Region region) {
+ // Remove the previous one because there is a new one incoming.
+ mTapExcludeRegions.remove(regionId);
+
+ if (region == null || region.isEmpty()) {
+ // The incoming region is invalid. Don't use it.
return;
}
- Rect region = mTapExcludeRects.get(regionId);
- if (region == null) {
- region = new Rect();
- }
- region.set(left, top, left + width, top + height);
- mTapExcludeRects.put(regionId, region);
+ mTapExcludeRegions.put(regionId, region);
}
/**
* Union the provided region with current region formed by this container.
*/
- void amendRegion(Region region, Rect boundingRegion) {
- for (int i = mTapExcludeRects.size() - 1; i>= 0 ; --i) {
- final Rect rect = mTapExcludeRects.valueAt(i);
- if (boundingRegion != null) {
- rect.intersect(boundingRegion);
+ void amendRegion(Region region, Rect bounds) {
+ for (int i = mTapExcludeRegions.size() - 1; i >= 0; --i) {
+ final Region r = mTapExcludeRegions.valueAt(i);
+ if (bounds != null) {
+ r.op(bounds, Region.Op.INTERSECT);
}
- region.union(rect);
+ region.op(r, Region.Op.UNION);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 20a874b..9fe4760 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -244,8 +244,6 @@
void calculateOutsets() {
if (mHasOutsets) {
InsetUtils.insetsBetweenFrames(mOutsetFrame, mContentFrame, mOutsets);
- } else {
- mOutsets.setEmpty();
}
}
@@ -373,7 +371,13 @@
* Sets whether the frame has outsets.
*/
public void setHasOutsets(boolean hasOutsets) {
+ if (mHasOutsets == hasOutsets) {
+ return;
+ }
mHasOutsets = hasOutsets;
+ if (!hasOutsets) {
+ mOutsets.setEmpty();
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index d3f3711..9d80425 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -414,7 +414,7 @@
OnHardKeyboardStatusChangeListener listener);
/** Returns true if a stack in the windowing mode is currently visible. */
- public abstract boolean isStackVisible(int windowingMode);
+ public abstract boolean isStackVisibleLw(int windowingMode);
/**
* Requests the window manager to resend the windows for accessibility.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4aa844f..20d02ee 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1392,11 +1392,9 @@
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
- final boolean hasStatusBarServicePermission =
- mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
- == PackageManager.PERMISSION_GRANTED;
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
- displayPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
+ displayPolicy.adjustWindowParamsLw(win, win.mAttrs, Binder.getCallingPid(),
+ Binder.getCallingUid());
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
res = displayPolicy.prepareAddWindowLw(win, attrs);
@@ -1932,6 +1930,11 @@
}
}
+ private boolean hasStatusBarPermission(int pid, int uid) {
+ return mContext.checkPermission(permission.STATUS_BAR, pid, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
@@ -1940,13 +1943,8 @@
SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
int result = 0;
boolean configChanged;
- final boolean hasStatusBarPermission =
- mContext.checkCallingOrSelfPermission(permission.STATUS_BAR)
- == PackageManager.PERMISSION_GRANTED;
- final boolean hasStatusBarServicePermission =
- mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
- == PackageManager.PERMISSION_GRANTED;
-
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
long origId = Binder.clearCallingIdentity();
final int displayId;
synchronized (mGlobalLock) {
@@ -1973,13 +1971,13 @@
int attrChanges = 0;
int flagChanges = 0;
if (attrs != null) {
- displayPolicy.adjustWindowParamsLw(win, attrs, hasStatusBarServicePermission);
+ displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
// if they don't have the permission, mask out the status bar bits
if (seq == win.mSeq) {
int systemUiVisibility = attrs.systemUiVisibility
| attrs.subtreeSystemUiVisibility;
if ((systemUiVisibility & DISABLE_MASK) != 0) {
- if (!hasStatusBarPermission) {
+ if (!hasStatusBarPermission(pid, uid)) {
systemUiVisibility &= ~DISABLE_MASK;
}
}
@@ -2050,7 +2048,6 @@
&& viewVisibility == View.VISIBLE;
boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0
|| becameVisible;
- final boolean isDefaultDisplay = win.isDefaultDisplay();
boolean focusMayChange = win.mViewVisibility != viewVisibility
|| ((flagChanges & FLAG_NOT_FOCUSABLE) != 0)
|| (!win.mRelayoutCalled);
@@ -6696,24 +6693,23 @@
}
/**
- * Update a tap exclude region with a rectangular area in the window identified by the provided
- * id. Touches down on this region will not:
+ * Update a tap exclude region in the window identified by the provided id. Touches down on this
+ * region will not:
* <ol>
* <li>Switch focus to this window.</li>
* <li>Move the display of this window to top.</li>
* <li>Send the touch events to this window.</li>
* </ol>
- * Passing an empty rect will remove the area from the exclude region of this window.
+ * Passing an invalid region will remove the area from the exclude region of this window.
*/
- void updateTapExcludeRegion(IWindow client, int regionId, int left, int top, int width,
- int height) {
+ void updateTapExcludeRegion(IWindow client, int regionId, Region region) {
synchronized (mGlobalLock) {
final WindowState callingWin = windowForClientLocked(null, client, false);
if (callingWin == null) {
Slog.w(TAG_WM, "Bad requesting window " + client);
return;
}
- callingWin.updateTapExcludeRegion(regionId, left, top, width, height);
+ callingWin.updateTapExcludeRegion(regionId, region);
}
}
@@ -7216,11 +7212,9 @@
}
@Override
- public boolean isStackVisible(int windowingMode) {
- synchronized (mGlobalLock) {
- final DisplayContent dc = getDefaultDisplayContentLocked();
- return dc.isStackVisible(windowingMode);
- }
+ public boolean isStackVisibleLw(int windowingMode) {
+ final DisplayContent dc = getDefaultDisplayContentLocked();
+ return dc.isStackVisible(windowingMode);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 1b4aa26..33561d3a 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -149,6 +149,8 @@
// Set to true if this process is currently temporarily whitelisted to start activities even if
// it's not in the foreground
private volatile boolean mAllowBackgroundActivityStarts;
+ // Set of UIDs of clients currently bound to this process
+ private volatile ArraySet<Integer> mBoundClientUids = new ArraySet<Integer>();
// Thread currently set for VR scheduling
int mVrThreadTid;
@@ -297,6 +299,11 @@
return mPendingUiClean;
}
+ /** @return {@code true} if the process registered to a display as a config listener. */
+ boolean registeredForDisplayConfigChanges() {
+ return mDisplayId != INVALID_DISPLAY;
+ }
+
void postPendingUiCleanMsg(boolean pendingUiClean) {
if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
@@ -368,6 +375,14 @@
return mAllowBackgroundActivityStarts;
}
+ public void setBoundClientUids(ArraySet<Integer> boundClientUids) {
+ mBoundClientUids = boundClientUids;
+ }
+
+ public ArraySet<Integer> getBoundClientUids() {
+ return mBoundClientUids;
+ }
+
public void setInstrumenting(boolean instrumenting,
boolean hasBackgroundActivityStartPrivileges) {
mInstrumenting = instrumenting;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f143c70..11288d2 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -72,6 +72,7 @@
import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
+import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
@@ -307,6 +308,9 @@
*/
private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration();
+ /** @see #isLastConfigReportedToClient() */
+ private boolean mLastConfigReportedToClient;
+
private final Configuration mTempConfiguration = new Configuration();
/**
@@ -1200,7 +1204,7 @@
}
boolean didFrameInsetsChange = setReportResizeHints();
- boolean configChanged = isConfigChanged();
+ boolean configChanged = !isLastConfigReportedToClient();
if (DEBUG_CONFIGURATION && configChanged) {
Slog.v(TAG_WM, "Win " + this + " config changed: " + getConfiguration());
}
@@ -1780,9 +1784,18 @@
return getDisplayContent().getBounds().equals(getBounds());
}
- /** Returns true if last applied config was not yet requested by client. */
- boolean isConfigChanged() {
- return !getLastReportedConfiguration().equals(getConfiguration());
+ /**
+ * @return {@code true} if last applied config was reported to the client already, {@code false}
+ * otherwise.
+ */
+ boolean isLastConfigReportedToClient() {
+ return mLastConfigReportedToClient;
+ }
+
+ @Override
+ void onMergedOverrideConfigurationChanged() {
+ super.onMergedOverrideConfigurationChanged();
+ mLastConfigReportedToClient = false;
}
void onWindowReplacementTimeout() {
@@ -2298,11 +2311,6 @@
void prepareWindowToDisplayDuringRelayout(boolean wasVisible) {
// We need to turn on screen regardless of visibility.
boolean hasTurnScreenOnFlag = (mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0;
- boolean allowTheaterMode =
- mWmService.mAllowTheaterModeWakeFromLayout || Settings.Global.getInt(
- mWmService.mContext.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0)
- == 0;
- boolean canTurnScreenOn = mAppToken == null || mAppToken.canTurnScreenOn();
// The screen will turn on if the following conditions are met
// 1. The window has the flag FLAG_TURN_SCREEN_ON
@@ -2316,6 +2324,11 @@
// be occurring while turning off the screen. This would lead to the screen incorrectly
// turning back on.
if (hasTurnScreenOnFlag) {
+ boolean allowTheaterMode = mWmService.mAllowTheaterModeWakeFromLayout
+ || Settings.Global.getInt(mWmService.mContext.getContentResolver(),
+ Settings.Global.THEATER_MODE_ON, 0) == 0;
+ boolean canTurnScreenOn = mAppToken == null || mAppToken.canTurnScreenOn();
+
if (allowTheaterMode && canTurnScreenOn && !mPowerManagerWrapper.isInteractive()) {
if (DEBUG_VISIBILITY || DEBUG_POWER) {
Slog.v(TAG, "Relayout window turning screen on: " + this);
@@ -2349,12 +2362,11 @@
private Configuration getProcessGlobalConfiguration() {
// For child windows we want to use the pid for the parent window in case the the child
// window was added from another process.
- final int pid = getParentWindow() != null ? getParentWindow().mSession.mPid : mSession.mPid;
+ final WindowState parentWindow = getParentWindow();
+ final int pid = parentWindow != null ? parentWindow.mSession.mPid : mSession.mPid;
final Configuration processConfig =
mWmService.mAtmService.getGlobalConfigurationForPid(pid);
- mTempConfiguration.setTo(processConfig == null
- ? mWmService.mRoot.getConfiguration() : processConfig);
- return mTempConfiguration;
+ return processConfig;
}
void getMergedConfiguration(MergedConfiguration outConfiguration) {
@@ -2365,6 +2377,7 @@
void setLastReportedMergedConfiguration(MergedConfiguration config) {
mLastReportedConfiguration.setTo(config);
+ mLastConfigReportedToClient = true;
}
void getLastReportedMergedConfiguration(MergedConfiguration config) {
@@ -2512,6 +2525,10 @@
}
boolean showLw(boolean doAnimation, boolean requestAnim) {
+ if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
+ // Already showing.
+ return false;
+ }
if (isHiddenFromUserLocked()) {
return false;
}
@@ -2532,10 +2549,6 @@
// This is an alert window that is currently force hidden.
return false;
}
- if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
- // Already showing.
- return false;
- }
if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);
if (doAnimation) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
@@ -2989,11 +3002,29 @@
return mAppToken.mFrozenMergedConfig.peek();
}
+ // If the process has not registered to any display to listen to the configuration change,
+ // we can simply return the mFullConfiguration as default.
+ if (!registeredForDisplayConfigChanges()) {
+ return super.getConfiguration();
+ }
+
// We use the process config this window is associated with as the based global config since
- // the process can override it config, but isn't part of the window hierarchy.
- final Configuration config = getProcessGlobalConfiguration();
- config.updateFrom(getMergedOverrideConfiguration());
- return config;
+ // the process can override its config, but isn't part of the window hierarchy.
+ mTempConfiguration.setTo(getProcessGlobalConfiguration());
+ mTempConfiguration.updateFrom(getMergedOverrideConfiguration());
+ return mTempConfiguration;
+ }
+
+ /** @return {@code true} if the process registered to a display as a config listener. */
+ private boolean registeredForDisplayConfigChanges() {
+ final WindowState parentWindow = getParentWindow();
+ final Session session = parentWindow != null ? parentWindow.mSession : mSession;
+ // System process or invalid process cannot register to display config change.
+ if (session.mPid == MY_PID || session.mPid < 0) return false;
+ WindowProcessController app =
+ mWmService.mAtmService.getProcessController(session.mPid, session.mUid);
+ if (app == null || !app.registeredForDisplayConfigChanges()) return false;
+ return true;
}
void reportResized() {
@@ -3511,7 +3542,10 @@
}
void transformClipRectFromScreenToSurfaceSpace(Rect clipRect) {
- if (mHScale >= 0) {
+ if (mHScale == 1 && mVScale == 1) {
+ return;
+ }
+ if (mHScale >= 0) {
clipRect.left = (int) (clipRect.left / mHScale);
clipRect.right = (int) Math.ceil(clipRect.right / mHScale);
}
@@ -4367,7 +4401,7 @@
// scale function because we want to round things to make the crop
// always round to a larger rect to ensure we don't crop too
// much and hide part of the window that should be seen.
- if (inSizeCompatMode() && mInvGlobalScale != 1.0f) {
+ if (mInvGlobalScale != 1.0f && inSizeCompatMode()) {
final float scale = mInvGlobalScale;
systemDecorRect.left = (int) (systemDecorRect.left * scale - 0.5f);
systemDecorRect.top = (int) (systemDecorRect.top * scale - 0.5f);
@@ -4422,7 +4456,12 @@
mWinAnimator.mEnteringAnimation = true;
- prepareWindowToDisplayDuringRelayout(wasVisible);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareToDisplay");
+ try {
+ prepareWindowToDisplayDuringRelayout(wasVisible);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
if ((attrChanges & FORMAT_CHANGED) != 0) {
// If the format can't be changed in place, preserve the old surface until the app draws
@@ -4837,10 +4876,10 @@
}
/**
- * Update a tap exclude region with a rectangular area identified by provided id. The requested
- * area will be clipped to the window bounds.
+ * Update a tap exclude region identified by provided id. The requested area will be clipped to
+ * the window bounds.
*/
- void updateTapExcludeRegion(int regionId, int left, int top, int width, int height) {
+ void updateTapExcludeRegion(int regionId, Region region) {
final DisplayContent currentDisplay = getDisplayContent();
if (currentDisplay == null) {
throw new IllegalStateException("Trying to update window not attached to any display.");
@@ -4854,7 +4893,7 @@
currentDisplay.mTapExcludeProvidingWindows.add(this);
}
- mTapExcludeRegionHolder.updateRegion(regionId, left, top, width, height);
+ mTapExcludeRegionHolder.updateRegion(regionId, region);
// Trigger touch exclude region update on current display.
currentDisplay.updateTouchExcludeRegion();
// Trigger touchable region update for this window.
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index acb9823..bef0f81 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -56,6 +56,7 @@
private float mSurfaceY = 0;
private int mSurfaceW = 0;
private int mSurfaceH = 0;
+ private Rect mSurfaceCrop = new Rect(0, 0, -1, -1);
// Initialize to the identity matrix.
private float mLastDsdx = 1;
@@ -171,26 +172,15 @@
}
}
- void disconnectInTransaction() {
- if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
- Slog.i(TAG, "Disconnecting client: " + this);
- }
-
- try {
- if (mSurfaceControl != null) {
- mSurfaceControl.disconnect();
- }
- } catch (RuntimeException e) {
- Slog.w(TAG, "Error disconnecting surface in: " + this, e);
- }
- }
-
void setCropInTransaction(Rect clipRect, boolean recoveringMemory) {
if (SHOW_TRANSACTIONS) logSurface(
"CROP " + clipRect.toShortString(), null);
try {
if (clipRect.width() > 0 && clipRect.height() > 0) {
- mSurfaceControl.setWindowCrop(clipRect);
+ if (!clipRect.equals(mSurfaceCrop)) {
+ mSurfaceControl.setWindowCrop(clipRect);
+ mSurfaceCrop.set(clipRect);
+ }
mHiddenForCrop = false;
updateVisibility();
} else {
@@ -212,7 +202,11 @@
"CLEAR CROP", null);
try {
Rect clipRect = new Rect(0, 0, -1, -1);
+ if (mSurfaceCrop.equals(clipRect)) {
+ return;
+ }
mSurfaceControl.setWindowCrop(clipRect);
+ mSurfaceCrop.set(clipRect);
} catch (RuntimeException e) {
Slog.w(TAG, "Error setting clearing crop of " + this, e);
if (!recoveringMemory) {
@@ -221,12 +215,6 @@
}
}
- void setLayerStackInTransaction(int layerStack) {
- if (mSurfaceControl != null) {
- mSurfaceControl.setLayerStack(layerStack);
- }
- }
-
void setPositionInTransaction(float left, float top, boolean recoveringMemory) {
setPosition(null, left, top, recoveringMemory);
}
diff --git a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
index 98bad93..3be5d31 100644
--- a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
+++ b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
@@ -81,11 +81,24 @@
* @hide
*/
public WmDisplayCutout calculateRelativeTo(Rect frame) {
+ if (mFrameSize == null) {
+ return this;
+ }
+ final int insetRight = mFrameSize.getWidth() - frame.right;
+ final int insetBottom = mFrameSize.getHeight() - frame.bottom;
+ if (frame.left == 0 && frame.top == 0 && insetRight == 0 && insetBottom == 0) {
+ return this;
+ }
+ if (frame.left >= mInner.getSafeInsetLeft()
+ && frame.top >= mInner.getSafeInsetTop()
+ && insetRight >= mInner.getSafeInsetRight()
+ && insetBottom >= mInner.getSafeInsetBottom()) {
+ return NO_CUTOUT;
+ }
if (mInner.isEmpty()) {
return this;
}
- return inset(frame.left, frame.top,
- mFrameSize.getWidth() - frame.right, mFrameSize.getHeight() - frame.bottom);
+ return inset(frame.left, frame.top, insetRight, insetBottom);
}
/**
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index 5e1ea89..98e4343 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -2,5 +2,5 @@
name: "default-permissions",
srcs: ["default-permissions.xsd"],
api_dir: "schema",
- package_name: "com.android.server.pm.permission",
+ package_name: "com.android.server.pm.permission.configfile",
}
diff --git a/services/core/xsd/default-permissions.xsd b/services/core/xsd/default-permissions.xsd
index d800a26..2e32be0 100644
--- a/services/core/xsd/default-permissions.xsd
+++ b/services/core/xsd/default-permissions.xsd
@@ -27,7 +27,7 @@
</xs:element>
<xs:complexType name="exception">
<xs:sequence>
- <xs:element name="permission" type="permission"/>
+ <xs:element name="permission" type="permission" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="package" type="xs:string"/>
<xs:attribute name="sha256-cert-digest" type="xs:string"/>
diff --git a/services/core/xsd/schema/current.txt b/services/core/xsd/schema/current.txt
index 4e67e5c..a2092e3 100644
--- a/services/core/xsd/schema/current.txt
+++ b/services/core/xsd/schema/current.txt
@@ -1,21 +1,20 @@
// Signature format: 2.0
-package com.android.server.pm.permission {
+package com.android.server.pm.permission.configfile {
public class Exception {
ctor public Exception();
method public String getBrand();
- method public com.android.server.pm.permission.Permission getPermission();
+ method public java.util.List<com.android.server.pm.permission.configfile.Permission> getPermission();
method public String getSha256CertDigest();
method public String get_package();
method public void setBrand(String);
- method public void setPermission(com.android.server.pm.permission.Permission);
method public void setSha256CertDigest(String);
method public void set_package(String);
}
public class Exceptions {
ctor public Exceptions();
- method public java.util.List<com.android.server.pm.permission.Exception> getException();
+ method public java.util.List<com.android.server.pm.permission.configfile.Exception> getException();
}
public class Permission {
@@ -28,7 +27,7 @@
public class XmlParser {
ctor public XmlParser();
- method public static com.android.server.pm.permission.Exceptions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static com.android.server.pm.permission.configfile.Exceptions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 633367a..aaa6d16 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11180,48 +11180,51 @@
@Override
public Intent createUserRestrictionSupportIntent(int userId, String userRestriction) {
- int source;
- long ident = mInjector.binderClearCallingIdentity();
+ final long ident = mInjector.binderClearCallingIdentity();
try {
- source = mUserManager.getUserRestrictionSource(userRestriction,
- UserHandle.of(userId));
+ final List<UserManager.EnforcingUser> sources = mUserManager
+ .getUserRestrictionSources(userRestriction, UserHandle.of(userId));
+ if (sources == null || sources.isEmpty()) {
+ // The restriction is not enforced.
+ return null;
+ } else if (sources.size() > 1) {
+ // In this case, we'll show an admin support dialog that does not
+ // specify the admin.
+ // TODO(b/128928355): if this restriction is enforced by multiple DPCs, return
+ // the admin for the calling user.
+ return DevicePolicyManagerService.this.createShowAdminSupportIntent(
+ null, userId);
+ }
+ final UserManager.EnforcingUser enforcingUser = sources.get(0);
+ final int sourceType = enforcingUser.getUserRestrictionSource();
+ final int enforcingUserId = enforcingUser.getUserHandle().getIdentifier();
+ if (sourceType == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) {
+ // Restriction was enforced by PO
+ final ComponentName profileOwner = mOwners.getProfileOwnerComponent(
+ enforcingUserId);
+ if (profileOwner != null) {
+ return DevicePolicyManagerService.this.createShowAdminSupportIntent(
+ profileOwner, enforcingUserId);
+ }
+ } else if (sourceType == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) {
+ // Restriction was enforced by DO
+ final Pair<Integer, ComponentName> deviceOwner =
+ mOwners.getDeviceOwnerUserIdAndComponent();
+ if (deviceOwner != null) {
+ return DevicePolicyManagerService.this.createShowAdminSupportIntent(
+ deviceOwner.second, deviceOwner.first);
+ }
+ } else if (sourceType == UserManager.RESTRICTION_SOURCE_SYSTEM) {
+ /*
+ * In this case, the user restriction is enforced by the system.
+ * So we won't show an admin support intent, even if it is also
+ * enforced by a profile/device owner.
+ */
+ return null;
+ }
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
- if ((source & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
- /*
- * In this case, the user restriction is enforced by the system.
- * So we won't show an admin support intent, even if it is also
- * enforced by a profile/device owner.
- */
- return null;
- }
- boolean enforcedByDo = (source & UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) != 0;
- boolean enforcedByPo = (source & UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) != 0;
- if (enforcedByDo && enforcedByPo) {
- // In this case, we'll show an admin support dialog that does not
- // specify the admin.
- return DevicePolicyManagerService.this.createShowAdminSupportIntent(null, userId);
- } else if (enforcedByPo) {
- final ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId);
- if (profileOwner != null) {
- return DevicePolicyManagerService.this
- .createShowAdminSupportIntent(profileOwner, userId);
- }
- // This could happen if another thread has changed the profile owner since we called
- // getUserRestrictionSource
- return null;
- } else if (enforcedByDo) {
- final Pair<Integer, ComponentName> deviceOwner
- = mOwners.getDeviceOwnerUserIdAndComponent();
- if (deviceOwner != null) {
- return DevicePolicyManagerService.this
- .createShowAdminSupportIntent(deviceOwner.second, deviceOwner.first);
- }
- // This could happen if another thread has changed the device owner since we called
- // getUserRestrictionSource
- return null;
- }
return null;
}
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 7ef0ac4..8f48f5b 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -58,6 +58,7 @@
name: "services.net",
srcs: ["java/**/*.java"],
static_libs: [
+ "dnsresolver_aidl_interface-java",
"netd_aidl_interface-java",
"networkstack-aidl-interfaces-java",
]
diff --git a/services/robotests/backup/Android.mk b/services/robotests/backup/Android.mk
index cc59b0c..bd4ebbd 100644
--- a/services/robotests/backup/Android.mk
+++ b/services/robotests/backup/Android.mk
@@ -26,7 +26,7 @@
LOCAL_PRIVILEGED_MODULE := true
LOCAL_STATIC_JAVA_LIBRARIES := \
- bmgrlib \
+ bmgr \
bu \
services.backup \
services.core \
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index cad71a2..08f6a37 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -722,6 +722,147 @@
assertEquals(expectedStats, newStatsRare);
}
+ /**
+ * Test getTimeUntilQuotaConsumedLocked when the determination is based within the bucket
+ * window.
+ */
+ @Test
+ public void testGetTimeUntilQuotaConsumedLocked_BucketWindow() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ // Close to RARE boundary.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (24 * HOUR_IN_MILLIS - 30 * SECOND_IN_MILLIS),
+ 30 * SECOND_IN_MILLIS, 5));
+ // Far away from FREQUENT boundary.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (7 * HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+ // Overlap WORKING_SET boundary.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS),
+ 3 * MINUTE_IN_MILLIS, 5));
+ // Close to ACTIVE boundary.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (9 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+
+ setStandbyBucket(RARE_INDEX);
+ assertEquals(30 * SECOND_IN_MILLIS,
+ mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ setStandbyBucket(FREQUENT_INDEX);
+ assertEquals(MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ setStandbyBucket(WORKING_INDEX);
+ assertEquals(5 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(7 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // ACTIVE window = allowed time, so jobs can essentially run non-stop until they reach the
+ // max execution time.
+ setStandbyBucket(ACTIVE_INDEX);
+ assertEquals(7 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
+
+ /**
+ * Test getTimeUntilQuotaConsumedLocked when the app is close to the max execution limit.
+ */
+ @Test
+ public void testGetTimeUntilQuotaConsumedLocked_MaxExecution() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ // Overlap boundary.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ now - (24 * HOUR_IN_MILLIS + 8 * MINUTE_IN_MILLIS), 4 * HOUR_IN_MILLIS, 5));
+
+ setStandbyBucket(WORKING_INDEX);
+ assertEquals(8 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ // Max time will phase out, so should use bucket limit.
+ assertEquals(10 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
+ // Close to boundary.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - (24 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS),
+ 4 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS, 5));
+
+ setStandbyBucket(WORKING_INDEX);
+ assertEquals(5 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(10 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
+ // Far from boundary.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ now - (20 * HOUR_IN_MILLIS), 4 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS, 5));
+
+ setStandbyBucket(WORKING_INDEX);
+ assertEquals(3 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ assertEquals(3 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
+
+ /**
+ * Test getTimeUntilQuotaConsumedLocked when the max execution time and bucket window time
+ * remaining are equal.
+ */
+ @Test
+ public void testGetTimeUntilQuotaConsumedLocked_EqualTimeRemaining() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ setStandbyBucket(FREQUENT_INDEX);
+
+ // Overlap boundary.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ now - (24 * HOUR_IN_MILLIS + 11 * MINUTE_IN_MILLIS),
+ 4 * HOUR_IN_MILLIS,
+ 5));
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+
+ // Both max and bucket time have 8 minutes left.
+ assertEquals(8 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ // Max time essentially free. Bucket time has 2 min phase out plus original 8 minute
+ // window time.
+ assertEquals(10 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
+ // Overlap boundary.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ now - (24 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 2 * MINUTE_IN_MILLIS, 5));
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ now - (20 * HOUR_IN_MILLIS),
+ 3 * HOUR_IN_MILLIS + 48 * MINUTE_IN_MILLIS,
+ 5));
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+
+ // Both max and bucket time have 8 minutes left.
+ assertEquals(8 * MINUTE_IN_MILLIS,
+ mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ // Max time only has one minute phase out. Bucket time has 2 minute phase out.
+ assertEquals(9 * MINUTE_IN_MILLIS,
+ mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
+
@Test
public void testIsWithinQuotaLocked_NeverApp() {
assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test.never", NEVER_INDEX));
@@ -1902,7 +2043,10 @@
// window, so as the package "reaches its quota" it will have more to keep running.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
createTimingSession(now - 2 * HOUR_IN_MILLIS,
- 10 * MINUTE_IN_MILLIS - remainingTimeMs, 1));
+ 10 * SECOND_IN_MILLIS - remainingTimeMs, 1));
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - HOUR_IN_MILLIS,
+ 9 * MINUTE_IN_MILLIS + 50 * SECOND_IN_MILLIS, 1));
assertEquals(remainingTimeMs, mQuotaController.getRemainingExecutionTimeLocked(jobStatus));
// Start the job.
@@ -1919,6 +2063,18 @@
// amount of remaining time left its quota.
assertEquals(remainingTimeMs,
mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
- verify(handler, atLeast(1)).sendMessageDelayed(any(), eq(remainingTimeMs));
+ // Handler is told to check when the quota will be consumed, not when the initial
+ // remaining time is over.
+ verify(handler, atLeast(1)).sendMessageDelayed(any(), eq(10 * SECOND_IN_MILLIS));
+ verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs));
+
+ // After 10 seconds, the job should finally be out of quota.
+ advanceElapsedClock(10 * SECOND_IN_MILLIS - remainingTimeMs);
+ // Wait for some extra time to allow for job processing.
+ verify(mJobSchedulerService,
+ timeout(12 * SECOND_IN_MILLIS).times(1))
+ .onControllerStateChanged();
+ assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ verify(handler, never()).sendMessageDelayed(any(), anyInt());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 04abeca1..f39c716 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -34,7 +34,9 @@
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
@@ -64,6 +66,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.platform.test.annotations.Presubmit;
import android.util.Log;
@@ -321,6 +324,14 @@
verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(false);
}
+ @Test
+ public void testExplicitSystenUserStartInBackground() {
+ setUpUser(UserHandle.USER_SYSTEM, 0);
+ assertFalse(mUserController.isSystemUserStarted());
+ assertTrue(mUserController.startUser(UserHandle.USER_SYSTEM, false, null));
+ assertTrue(mUserController.isSystemUserStarted());
+ }
+
private void setUpUser(int userId, int flags) {
UserInfo userInfo = new UserInfo(userId, "User" + userId, flags);
when(mInjector.mUserManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo);
@@ -417,6 +428,12 @@
@Override
void reportCurWakefulnessUsageEvent() {
}
+
+ @Override
+ boolean isRuntimeRestarted() {
+ // to pass all metrics related calls
+ return true;
+ }
}
private static class TestHandler extends Handler {
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 4b3d9cf..0792414 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -1148,6 +1148,11 @@
return null;
}
+ @Override
+ public String getAttentionServicePackageName() throws RemoteException {
+ return null;
+ }
+
public String getIncidentReportApproverPackageName() throws RemoteException {
return null;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 5b19700..cbabb0b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -100,7 +100,6 @@
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.File;
@@ -242,29 +241,23 @@
final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>();
// UM.setApplicationRestrictions() will save to appRestrictions.
- doAnswer(new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) throws Throwable {
- String pkg = (String) invocation.getArguments()[0];
- Bundle bundle = (Bundle) invocation.getArguments()[1];
- UserHandle user = (UserHandle) invocation.getArguments()[2];
+ doAnswer((Answer<Void>) invocation -> {
+ String pkg = (String) invocation.getArguments()[0];
+ Bundle bundle = (Bundle) invocation.getArguments()[1];
+ UserHandle user = (UserHandle) invocation.getArguments()[2];
- appRestrictions.put(Pair.create(pkg, user), bundle);
+ appRestrictions.put(Pair.create(pkg, user), bundle);
- return null;
- }
+ return null;
}).when(getServices().userManager).setApplicationRestrictions(
anyString(), nullable(Bundle.class), any(UserHandle.class));
// UM.getApplicationRestrictions() will read from appRestrictions.
- doAnswer(new Answer<Bundle>() {
- @Override
- public Bundle answer(InvocationOnMock invocation) throws Throwable {
- String pkg = (String) invocation.getArguments()[0];
- UserHandle user = (UserHandle) invocation.getArguments()[1];
+ doAnswer((Answer<Bundle>) invocation -> {
+ String pkg = (String) invocation.getArguments()[0];
+ UserHandle user = (UserHandle) invocation.getArguments()[1];
- return appRestrictions.get(Pair.create(pkg, user));
- }
+ return appRestrictions.get(Pair.create(pkg, user));
}).when(getServices().userManager).getApplicationRestrictions(
anyString(), any(UserHandle.class));
@@ -2243,11 +2236,13 @@
intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
assertNull(intent);
- // Permission that is set by device owner returns correct intent
- when(getServices().userManager.getUserRestrictionSource(
+ // UM.getUserRestrictionSources() will return a list of size 1 with the caller resource.
+ doAnswer((Answer<List<UserManager.EnforcingUser>>) invocation -> Collections.singletonList(
+ new UserManager.EnforcingUser(
+ UserHandle.myUserId(), UserManager.RESTRICTION_SOURCE_DEVICE_OWNER))
+ ).when(getServices().userManager).getUserRestrictionSources(
eq(UserManager.DISALLOW_ADJUST_VOLUME),
- eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
- .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
+ eq(UserHandle.getUserHandleForUid(UserHandle.myUserId())));
intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
assertNotNull(intent);
assertEquals(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS, intent.getAction());
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index aa3135f..3ff85c8 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -29,6 +29,7 @@
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a9eb6ec..4332fea 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -79,6 +79,7 @@
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.ICompanionDeviceManager;
@@ -92,6 +93,7 @@
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.drawable.Icon;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Binder;
@@ -101,6 +103,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
@@ -120,9 +123,6 @@
import android.util.ArraySet;
import android.util.AtomicFile;
-import androidx.annotation.Nullable;
-import androidx.test.InstrumentationRegistry;
-
import com.android.internal.R;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.statusbar.NotificationVisibility;
@@ -149,7 +149,6 @@
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
@@ -160,6 +159,9 @@
import java.util.Set;
import java.util.function.Consumer;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -226,23 +228,21 @@
@Mock
AppOpsManager mAppOpsManager;
@Mock
- private UserManagerService mUserMangerService;
- @Mock
private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback
mNotificationAssistantAccessGrantedCallback;
+ @Mock
+ UserManager mUm;
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
int countSystemChecks = 0;
boolean isSystemUid = true;
int countLogSmartSuggestionsVisible = 0;
- UserManagerService mUserManagerService;
@Nullable
NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback;
- TestableNotificationManagerService(Context context, UserManagerService userManagerService) {
+ TestableNotificationManagerService(Context context) {
super(context);
- mUserManagerService = userManagerService;
}
@Override
@@ -279,11 +279,6 @@
}
@Override
- UserManagerService getUserManagerService() {
- return mUserManagerService;
- }
-
- @Override
protected void setNotificationAssistantAccessGrantedForUserInternal(
ComponentName assistant, int userId, boolean granted) {
if (mNotificationAssistantAccessGrantedCallback != null) {
@@ -326,7 +321,7 @@
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
- mService = new TestableNotificationManagerService(mContext, mUserMangerService);
+ mService = new TestableNotificationManagerService(mContext);
// Use this testable looper.
mTestableLooper = TestableLooper.get(this);
@@ -379,7 +374,7 @@
mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
mGroupHelper, mAm, mAppUsageStats,
mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
- mAppOpsManager);
+ mAppOpsManager, mUm);
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
@@ -507,6 +502,13 @@
false);
}
+ private Notification.BubbleMetadata.Builder getBasicBubbleMetadataBuilder() {
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ return new Notification.BubbleMetadata.Builder()
+ .setIntent(pi)
+ .setIcon(Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon));
+ }
+
@Test
public void testCreateNotificationChannels_SingleChannel() throws Exception {
final NotificationChannel channel =
@@ -1920,8 +1922,8 @@
}
@Test
- public void testHasCompanionDevice_noService() throws Exception {
- mService = new TestableNotificationManagerService(mContext, mUserMangerService);
+ public void testHasCompanionDevice_noService() {
+ mService = new TestableNotificationManagerService(mContext);
assertFalse(mService.hasCompanionDevice(mListener));
}
@@ -2623,7 +2625,7 @@
+ "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+ "</dnd_apps>"
+ "</notification-policy>";
- when(mUserMangerService.isManagedProfile(10)).thenReturn(true);
+ when(mUm.isManagedProfile(10)).thenReturn(true);
mService.readPolicyXml(
new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
true,
@@ -2647,7 +2649,7 @@
+ "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+ "</dnd_apps>"
+ "</notification-policy>";
- when(mUserMangerService.isManagedProfile(10)).thenReturn(false);
+ when(mUm.isManagedProfile(10)).thenReturn(false);
mService.readPolicyXml(
new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
true,
@@ -4290,6 +4292,137 @@
.onGranted(eq(xmlConfig), eq(0), eq(true));
}
+ @Test
+ public void testFlagBubbleNotifs_flagIfAllowed() throws RemoteException {
+ // Bubbles are allowed!
+ mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
+ when(mPreferencesHelper.getNotificationChannel(
+ anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+ mTestNotificationChannel);
+ when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+ mTestNotificationChannel.getImportance());
+
+ // Notif with bubble metadata
+ Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .setBubbleMetadata(data)
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
+ nb.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
+ nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+ waitForIdle();
+
+ // yes allowed, yes bubble
+ assertTrue(mService.getNotificationRecord(
+ sbn.getKey()).getNotification().isBubbleNotification());
+ }
+
+ @Test
+ public void testFlagBubbleNotifs_noFlagIfNotAllowed() throws RemoteException {
+ // Bubbles are NOT allowed!
+ mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(false);
+ when(mPreferencesHelper.getNotificationChannel(
+ anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+ mTestNotificationChannel);
+ when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+ mTestNotificationChannel.getImportance());
+
+ // Notif with bubble metadata
+ Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .setBubbleMetadata(data)
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
+ nb.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ // Post the notification
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
+ nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+ waitForIdle();
+
+ // not allowed, no bubble
+ assertFalse(mService.getNotificationRecord(
+ sbn.getKey()).getNotification().isBubbleNotification());
+ }
+
+ @Test
+ public void testFlagBubbleNotifs_noFlagIfNotBubble() throws RemoteException {
+ // Bubbles are allowed!
+ mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
+ when(mPreferencesHelper.getNotificationChannel(
+ anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+ mTestNotificationChannel);
+ when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+ mTestNotificationChannel.getImportance());
+
+ // Notif WITHOUT bubble metadata
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
+ nb.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ // Post the notification
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
+ nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+ waitForIdle();
+
+ // no bubble metadata, no bubble
+ assertFalse(mService.getNotificationRecord(
+ sbn.getKey()).getNotification().isBubbleNotification());
+ }
+
+ @Test
+ public void testFlagBubbleNotifs_noFlagIfChannelNotBubble() throws RemoteException {
+ // Bubbles are allowed!
+ mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
+ when(mPreferencesHelper.getNotificationChannel(
+ anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+ mTestNotificationChannel);
+ when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+ mTestNotificationChannel.getImportance());
+
+ // But not on this channel!
+ mTestNotificationChannel.setAllowBubbles(false);
+
+ // Notif with bubble metadata
+ Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .setBubbleMetadata(data)
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
+ nb.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ // Post the notification
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
+ nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+ waitForIdle();
+
+ // channel not allowed, no bubble
+ assertFalse(mService.getNotificationRecord(
+ sbn.getKey()).getNotification().isBubbleNotification());
+ }
public void testGetAllowedAssistantCapabilities() throws Exception {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index e375195..ee09c7e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -952,7 +952,31 @@
}
@Test
- public void testApplyImportanceAdjustmentsForNonOemLockedChannels() {
+ public void testIgnoreImportanceAdjustmentsForDefaultAppLockedChannels() {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+ channel.setImportanceLockedByCriticalDeviceFunction(true);
+
+ StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /* defaultLights */, groupId /* group */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+ assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+
+ Bundle bundle = new Bundle();
+ bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
+ Adjustment adjustment = new Adjustment(
+ PKG_O, record.getKey(), bundle, "", record.getUserId());
+
+ record.addAdjustment(adjustment);
+ record.applyAdjustments();
+ record.calculateImportance();
+
+ assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+ }
+
+ @Test
+ public void testApplyImportanceAdjustmentsForNonOemDefaultAppLockedChannels() {
NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
channel.setImportanceLockedByOEM(false);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 39e47ec..87f10a4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -62,11 +62,9 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableContentResolver;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Xml;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
@@ -91,6 +89,9 @@
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class PreferencesHelperTest extends UiServiceTestCase {
@@ -2442,4 +2443,153 @@
assertEquals(IMPORTANCE_HIGH,
mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
}
+
+ @Test
+ public void testUpdateDefaultApps_add_multiUser() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+ // different uids, same package
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+ mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false);
+ mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true);
+
+ ArraySet<String> toAdd = new ArraySet<>();
+ toAdd.add(PKG_O);
+ mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ assertFalse(mHelper.getNotificationChannel(
+ PKG_O, UserHandle.PER_USER_RANGE + 1, c.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ }
+
+ @Test
+ public void testUpdateDefaultApps_add_onlyGivenPkg() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false);
+
+ ArraySet<String> toAdd = new ArraySet<>();
+ toAdd.add(PKG_O);
+ mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ }
+
+ @Test
+ public void testUpdateDefaultApps_remove() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ // different uids, same package
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+ mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false);
+
+ ArraySet<String> toAdd = new ArraySet<>();
+ toAdd.add(PKG_O);
+ mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+
+ ArraySet<String> toRemove = new ArraySet<>();
+ toRemove.add(PKG_O);
+ mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), toRemove, null);
+
+ assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ }
+
+ @Test
+ public void testUpdateDefaultApps_addAndRemove() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false);
+
+ ArraySet<String> toAdd = new ArraySet<>();
+ toAdd.add(PKG_O);
+ mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+
+ // now the default is PKG_N_MR1
+ ArraySet<String> toRemove = new ArraySet<>();
+ toRemove.add(PKG_O);
+ toAdd = new ArraySet<>();
+ toAdd.add(PKG_N_MR1);
+ mHelper.updateDefaultApps(USER.getIdentifier(), toRemove, toAdd);
+
+ assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ }
+
+ @Test
+ public void testUpdateDefaultApps_appDoesNotExist_noCrash() {
+ ArraySet<String> toAdd = new ArraySet<>();
+ toAdd.add(PKG_O);
+ ArraySet<String> toRemove = new ArraySet<>();
+ toRemove.add(PKG_N_MR1);
+ mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), toRemove, toAdd);
+ }
+
+ @Test
+ public void testUpdateDefaultApps_channelDoesNotExistYet() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+ ArraySet<String> toAdd = new ArraySet<>();
+ toAdd.add(PKG_O);
+ mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+
+ mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false);
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+ .isImportanceLockedByCriticalDeviceFunction());
+ }
+
+ @Test
+ public void testUpdateNotificationChannel_defaultAppLockedImportance() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+ ArraySet<String> toAdd = new ArraySet<>();
+ toAdd.add(PKG_O);
+ mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+ NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
+ update.setAllowBubbles(false);
+
+ mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
+
+ assertEquals(IMPORTANCE_HIGH,
+ mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+ assertEquals(false,
+ mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
+
+ mHelper.updateNotificationChannel(PKG_O, UID_O, update, false);
+
+ assertEquals(IMPORTANCE_HIGH,
+ mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
new file mode 100644
index 0000000..91d3e5e
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
+import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MAX;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.app.role.RoleManager.ROLE_DIALER;
+import static android.app.role.RoleManager.ROLE_EMERGENCY;
+import static android.app.role.RoleManager.ROLE_SMS;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Build.VERSION_CODES.O_MR1;
+import static android.os.Build.VERSION_CODES.P;
+import static android.service.notification.Adjustment.KEY_IMPORTANCE;
+import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+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.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.IActivityManager;
+import android.app.INotificationManager;
+import android.app.ITransientNotification;
+import android.app.IUriGrantsManager;
+import android.app.Notification;
+import android.app.Notification.MessagingStyle.Message;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.app.role.RoleManager;
+import android.app.usage.UsageStatsManagerInternal;
+import android.companion.ICompanionDeviceManager;
+import android.content.ComponentName;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.UserInfo;
+import android.graphics.Color;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.DeviceConfig;
+import android.provider.MediaStore;
+import android.provider.Settings;
+import android.service.notification.Adjustment;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
+import android.service.notification.NotifyingApp;
+import android.service.notification.StatusBarNotification;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.testing.TestablePermissions;
+import android.text.Html;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+
+import com.android.internal.R;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.server.LocalServices;
+import com.android.server.UiServiceTestCase;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+import com.android.server.notification.NotificationManagerService.NotificationAssistants;
+import com.android.server.notification.NotificationManagerService.NotificationListeners;
+import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
+
+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.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class RoleObserverTest extends UiServiceTestCase {
+ private TestableNotificationManagerService mService;
+ private NotificationManagerService.RoleObserver mRoleObserver;
+
+ private TestableContext mContext = spy(getContext());
+
+ @Mock
+ private PreferencesHelper mPreferencesHelper;
+ @Mock
+ private UserManager mUm;
+ @Mock
+ private Executor mExecutor;
+ @Mock
+ private RoleManager mRoleManager;
+
+ private List<UserInfo> mUsers;
+
+ private static class TestableNotificationManagerService extends NotificationManagerService {
+
+ TestableNotificationManagerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void handleSavePolicyFile() {
+ return;
+ }
+
+ @Override
+ protected void loadPolicyFile() {
+ return;
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ LocalServices.removeServiceForTest(WindowManagerInternal.class);
+ LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class));
+
+ mUsers = new ArrayList<>();
+ mUsers.add(new UserInfo(0, "system", 0));
+ mUsers.add(new UserInfo(10, "second", 0));
+ when(mUm.getUsers()).thenReturn(mUsers);
+
+ mService = new TestableNotificationManagerService(mContext);
+ mRoleObserver = mService.new RoleObserver(mRoleManager, mExecutor);
+
+ try {
+ mService.init(mock(Looper.class),
+ mock(IPackageManager.class), mock(PackageManager.class),
+ mock(LightsManager.class),
+ mock(NotificationListeners.class), mock(NotificationAssistants.class),
+ mock(ConditionProviders.class), mock(ICompanionDeviceManager.class),
+ mock(SnoozeHelper.class), mock(NotificationUsageStats.class),
+ mock(AtomicFile.class), mock(ActivityManager.class),
+ mock(GroupHelper.class), mock(IActivityManager.class),
+ mock(UsageStatsManagerInternal.class),
+ mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class),
+ mock(UriGrantsManagerInternal.class),
+ mock(AppOpsManager.class), mUm);
+ } catch (SecurityException e) {
+ if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
+ throw e;
+ }
+ }
+ mService.setPreferencesHelper(mPreferencesHelper);
+ }
+
+ @Test
+ public void testInit() {
+ List<String> dialer0 = new ArrayList<>();
+ dialer0.add("dialer");
+ List<String> emer0 = new ArrayList<>();
+ emer0.add("emergency");
+ List<String> sms10 = new ArrayList<>();
+ sms10.add("sms");
+ when(mRoleManager.getRoleHoldersAsUser(
+ ROLE_DIALER,
+ mUsers.get(0).getUserHandle())).
+ thenReturn(dialer0);
+ when(mRoleManager.getRoleHoldersAsUser(
+ ROLE_EMERGENCY,
+ mUsers.get(0).getUserHandle())).
+ thenReturn(emer0);
+ when(mRoleManager.getRoleHoldersAsUser(
+ ROLE_SMS,
+ mUsers.get(1).getUserHandle())).
+ thenReturn(sms10);
+
+ mRoleObserver.init();
+
+ // verify internal records of current state of the world
+ assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(
+ ROLE_DIALER, dialer0.get(0), mUsers.get(0).id));
+ assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
+ ROLE_DIALER, dialer0.get(0), mUsers.get(1).id));
+ assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
+ ROLE_SMS, dialer0.get(0), mUsers.get(1).id));
+
+ assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(
+ ROLE_EMERGENCY, emer0.get(0), mUsers.get(0).id));
+ assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
+ ROLE_EMERGENCY, emer0.get(0), mUsers.get(1).id));
+
+ assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
+ ROLE_SMS, sms10.get(0), mUsers.get(0).id));
+ assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
+ ROLE_DIALER, sms10.get(0), mUsers.get(0).id));
+ assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(
+ ROLE_SMS, sms10.get(0), mUsers.get(1).id));
+
+ // make sure we're listening to updates
+ verify(mRoleManager, times(1)).addOnRoleHoldersChangedListenerAsUser(
+ eq(mExecutor), any(), eq(UserHandle.ALL));
+
+ // make sure we told pref helper about the state of the world
+ verify(mPreferencesHelper, times(1)).updateDefaultApps(0, null, new ArraySet<>(dialer0));
+ verify(mPreferencesHelper, times(1)).updateDefaultApps(0, null, new ArraySet<>(emer0));
+ verify(mPreferencesHelper, times(1)).updateDefaultApps(10, null, new ArraySet<>(sms10));
+ }
+
+ @Test
+ public void testSwapDefault() {
+ List<String> dialer0 = new ArrayList<>();
+ dialer0.add("dialer");
+
+ when(mRoleManager.getRoleHoldersAsUser(
+ ROLE_DIALER,
+ mUsers.get(0).getUserHandle())).
+ thenReturn(dialer0);
+
+ mRoleObserver.init();
+
+ List<String> newDefault = new ArrayList<>();
+ newDefault.add("phone");
+
+ when(mRoleManager.getRoleHoldersAsUser(
+ ROLE_DIALER,
+ mUsers.get(0).getUserHandle())).
+ thenReturn(newDefault);
+
+ mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(0));
+
+ verify(mPreferencesHelper, times(1)).updateDefaultApps(
+ 0, new ArraySet<>(dialer0), new ArraySet<>(newDefault));
+ }
+
+ @Test
+ public void testSwapDefault_multipleOverlappingApps() {
+ List<String> dialer0 = new ArrayList<>();
+ dialer0.add("dialer");
+ dialer0.add("phone");
+
+ when(mRoleManager.getRoleHoldersAsUser(
+ ROLE_DIALER,
+ mUsers.get(0).getUserHandle())).
+ thenReturn(dialer0);
+
+ mRoleObserver.init();
+
+ assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 0));
+ assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "emerPhone", 0));
+ assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0));
+
+ List<String> newDefault = new ArrayList<>();
+ newDefault.add("phone");
+ newDefault.add("emerPhone");
+
+ when(mRoleManager.getRoleHoldersAsUser(
+ ROLE_DIALER,
+ mUsers.get(0).getUserHandle())).
+ thenReturn(newDefault);
+
+ mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(0));
+
+ ArraySet<String> expectedRemove = new ArraySet<>();
+ expectedRemove.add("dialer");
+ ArraySet<String> expectedAdd = new ArraySet<>();
+ expectedAdd.add("emerPhone");
+
+ verify(mPreferencesHelper, times(1)).updateDefaultApps(
+ 0, expectedRemove, expectedAdd);
+
+ assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 0));
+ assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "emerPhone", 0));
+ assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0));
+ }
+
+ @Test
+ public void testSwapDefault_newUser() {
+ List<String> dialer0 = new ArrayList<>();
+ dialer0.add("dialer");
+
+ when(mRoleManager.getRoleHoldersAsUser(
+ ROLE_DIALER,
+ mUsers.get(0).getUserHandle())).
+ thenReturn(dialer0);
+
+ mRoleObserver.init();
+
+ List<String> dialer10 = new ArrayList<>();
+ dialer10.add("phone");
+
+ when(mRoleManager.getRoleHoldersAsUser(
+ ROLE_DIALER,
+ mUsers.get(1).getUserHandle())).
+ thenReturn(dialer10);
+
+ mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(10));
+
+ ArraySet<String> expectedRemove = new ArraySet<>();
+ ArraySet<String> expectedAdd = new ArraySet<>();
+ expectedAdd.add("phone");
+
+ verify(mPreferencesHelper, times(1)).updateDefaultApps(
+ 10, expectedRemove, expectedAdd);
+
+ assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 10));
+ assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0));
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 2ab48a9..5cef38d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -38,6 +38,7 @@
import android.content.res.Resources;
import android.graphics.Matrix;
import android.graphics.RectF;
+import android.os.Binder;
import android.os.IBinder;
import android.testing.TestableResources;
import android.util.Pair;
@@ -98,7 +99,8 @@
}
void addWindow(WindowState win) {
- mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs, true /* hasStatusBarPermission */);
+ mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs, Binder.getCallingPid(),
+ Binder.getCallingUid());
assertEquals(WindowManagerGlobal.ADD_OKAY,
mDisplayPolicy.prepareAddWindowLw(win, win.mAttrs));
win.mHasSurface = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 88ac96d..4f03726 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -181,15 +181,10 @@
public void testDeferFinish() {
// Start animation
- mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec,
- true /* hidden */);
- final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
- OnAnimationFinishedCallback.class);
- assertAnimating(mDeferFinishAnimatable);
- verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+ final OnAnimationFinishedCallback onFinishedCallback = startDeferFinishAnimatable(mSpec);
// Finish the animation but then make sure we are deferring.
- callbackCaptor.getValue().onAnimationFinished(mSpec);
+ onFinishedCallback.onAnimationFinished(mSpec);
assertAnimating(mDeferFinishAnimatable);
// Now end defer finishing.
@@ -199,6 +194,36 @@
verify(mTransaction).remove(eq(mDeferFinishAnimatable.mLeash));
}
+ @Test
+ public void testDeferFinishDoNotFinishNextAnimation() {
+ // Start the first animation.
+ final OnAnimationFinishedCallback onFinishedCallback = startDeferFinishAnimatable(mSpec);
+ onFinishedCallback.onAnimationFinished(mSpec);
+ // The callback is the resetAndInvokeFinish in {@link SurfaceAnimator#getFinishedCallback}.
+ final Runnable firstDeferFinishCallback = mDeferFinishAnimatable.mEndDeferFinishCallback;
+
+ // Start the second animation.
+ mDeferFinishAnimatable.mSurfaceAnimator.cancelAnimation();
+ startDeferFinishAnimatable(mSpec2);
+ mDeferFinishAnimatable.mFinishedCallbackCalled = false;
+
+ // Simulate the first deferred callback is executed from
+ // {@link AnimatingAppWindowTokenRegistry#endDeferringFinished}.
+ firstDeferFinishCallback.run();
+ // The second animation should not be finished.
+ assertFalse(mDeferFinishAnimatable.mFinishedCallbackCalled);
+ }
+
+ private OnAnimationFinishedCallback startDeferFinishAnimatable(AnimationAdapter anim) {
+ mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, anim,
+ true /* hidden */);
+ final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
+ OnAnimationFinishedCallback.class);
+ assertAnimating(mDeferFinishAnimatable);
+ verify(anim).startAnimation(any(), any(), callbackCaptor.capture());
+ return callbackCaptor.getValue();
+ }
+
private void assertAnimating(MyAnimatable animatable) {
assertTrue(animatable.mSurfaceAnimator.isAnimating());
assertNotNull(animatable.mSurfaceAnimator.getAnimation());
diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp
index 4359978..3e60ad4 100644
--- a/startop/iorap/tests/Android.bp
+++ b/startop/iorap/tests/Android.bp
@@ -16,32 +16,48 @@
java_library {
name: "libiorap-java-test-lib",
srcs: ["src/**/*.kt"],
-
static_libs: [
- // Non-test dependencies
-
- // library under test
- "services.startop.iorap",
- // need the system_server code to be on the classpath,
- "services.core",
-
- // Test Dependencies
-
- // test android dependencies
- "platform-test-annotations",
- "androidx.test.rules",
- // test framework dependencies
- "mockito-target-inline-minus-junit4",
- // "mockito-target-minus-junit4",
+ // Non-test dependencies
+ // library under test
+ "services.startop.iorap",
+ // need the system_server code to be on the classpath,
+ "services.core",
+ // Test Dependencies
+ // test android dependencies
+ "platform-test-annotations",
+ "androidx.test.rules",
+ // test framework dependencies
+ "mockito-target-inline-minus-junit4",
+ // "mockito-target-minus-junit4",
// Mockito also requires JNI (see Android.mk)
// and android:debuggable=true (see AndroidManifest.xml)
- "truth-prebuilt",
+ "truth-prebuilt",
],
-
// sdk_version: "current",
// certificate: "platform",
-
- libs: ["android.test.base", "android.test.runner"],
-
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
// test_suites: ["device-tests"],
}
+
+android_test {
+ name: "libiorap-java-tests",
+ dxflags: ["--multi-dex"],
+ test_suites: ["device-tests"],
+ static_libs: ["libiorap-java-test-lib"],
+ compile_multilib: "both",
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ "libmultiplejvmtiagentsinterferenceagent",
+ ],
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+ // Use private APIs
+ certificate: "platform",
+ platform_apis: true,
+}
diff --git a/startop/iorap/tests/Android.mk b/startop/iorap/tests/Android.mk
deleted file mode 100644
index fa8c8b5..0000000
--- a/startop/iorap/tests/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# android_test does not support JNI libraries
-# TODO: once b/80095087 is fixed, rewrite this back to android_test
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_DX_FLAGS := --multi-dex
-
-LOCAL_PACKAGE_NAME := libiorap-java-tests
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- libiorap-java-test-lib
-
-LOCAL_MULTILIB := both
-
-LOCAL_JNI_SHARED_LIBRARIES := \
- libdexmakerjvmtiagent \
- libstaticjvmtiagent \
- libmultiplejvmtiagentsinterferenceagent
-
-LOCAL_JAVA_LIBRARIES := \
- android.test.base \
- android.test.runner
-
-# Use private APIs
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# Disable presubmit test until it works with disabled iorap by default.
-LOCAL_PRESUBMIT_DISABLED := true
-
-include $(BUILD_PACKAGE)
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index a15f959..a1c5bbe 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -27,8 +27,8 @@
/**
* Defines available network information which includes corresponding subscription id,
- * network plmns and corresponding priority to be used for network selection by Alternative Network
- * Service.
+ * network plmns and corresponding priority to be used for network selection by Opportunistic
+ * Network Service when passed through {@link TelephonyManager#updateAvailableNetworks}
*/
public final class AvailableNetworkInfo implements Parcelable {
@@ -55,15 +55,19 @@
/**
* Priority for the subscription id.
- * Priorities are in the range of 1 to 3 where 1
- * has the highest priority.
+ * Priorities are in the range of {@link AvailableNetworkInfo#PRIORITY_LOW} to
+ * {@link AvailableNetworkInfo#PRIORITY_HIGH}
+ * Among all networks available after network scan, subId with highest priority is chosen
+ * for network selection. If there are more than one subId with highest priority then the
+ * network with highest RSRP is chosen.
*/
private int mPriority;
/**
* Describes the List of PLMN ids (MCC-MNC) associated with mSubId.
- * If this entry is left empty, then the platform software will not scan the network
- * to revalidate the input else platform will scan and verify specified PLMNs are available.
+ * Opportunistic Network Service will scan and verify specified PLMNs are available.
+ * If this entry is left empty, then the Opportunistic Network Service will not scan the network
+ * to validate the network availability.
*/
private ArrayList<String> mMccMncs;
@@ -71,8 +75,8 @@
* Returns the frequency bands associated with the {@link #getMccMncs() MCC/MNCs}.
* Opportunistic network service will use these bands to scan.
*
- * When no specific bands are specified (empty array or null) CBRS band (B48) will be
- * used for network scan.
+ * When no specific bands are specified (empty array or null) CBRS band
+ * {@link AccessNetworkConstants.EutranBand.BAND_48} will be used for network scan.
*
* See {@link AccessNetworkConstants} for details.
*/
@@ -89,8 +93,12 @@
}
/**
- * Return priority for the subscription id. Valid value will be within
- * [{@link AvailableNetworkInfo#PRIORITY_HIGH}, {@link AvailableNetworkInfo#PRIORITY_LOW}]
+ * Return priority for the subscription id.
+ * Priorities are in the range of {@link AvailableNetworkInfo#PRIORITY_LOW} to
+ * {@link AvailableNetworkInfo#PRIORITY_HIGH}
+ * Among all networks available after network scan, subId with highest priority is chosen
+ * for network selection. If there are more than one subId with highest priority then the
+ * network with highest RSRP is chosen.
* @return priority level
*/
public int getPriority() {
@@ -99,8 +107,9 @@
/**
* Return List of PLMN ids (MCC-MNC) associated with the sub ID.
- * If this entry is left empty, then the platform software will not scan the network
- * to revalidate the input.
+ * Opportunistic Network Service will scan and verify specified PLMNs are available.
+ * If this entry is left empty, then the Opportunistic Network Service will not scan the network
+ * to validate the network availability.
* @return list of PLMN ids
*/
public @NonNull List<String> getMccMncs() {
@@ -112,6 +121,9 @@
*
* The returned value is defined in either of {@link AccessNetworkConstants.GeranBand},
* {@link AccessNetworkConstants.UtranBand} and {@link AccessNetworkConstants.EutranBand}
+ * See {@link AccessNetworkConstants.AccessNetworkType} for details regarding different network
+ * types. When no specific bands are specified (empty array or null) CBRS band
+ * {@link AccessNetworkConstants.EutranBand#BAND_48} will be used for network scan.
*/
public @NonNull List<Integer> getBands() {
return (List<Integer>) mBands.clone();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fffa935..0b44367 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2571,6 +2571,22 @@
"emergency_number_prefix_string_array";
/**
+ * Smart forwarding config. Smart forwarding is a feature to configure call forwarding to a
+ * different SIM in the device when one SIM is not reachable. The config here specifies a smart
+ * forwarding component that will launch UI for changing the configuration. An empty string
+ * indicates that no smart forwarding component is specified.
+ *
+ * Currently, only one non-empty configuration of smart forwarding component within system will
+ * be used when multiple SIMs are inserted.
+ *
+ * Empty string by default.
+ *
+ * @hide
+ */
+ public static final String KEY_SMART_FORWARDING_CONFIG_COMPONENT_NAME_STRING =
+ "smart_forwarding_config_component_name_string";
+
+ /**
* Indicates when a carrier has a primary subscription and an opportunistic subscription active,
* and when Internet data is switched to opportunistic network, whether to still show
* signal bar of primary network. By default it will be false, meaning whenever data
@@ -3130,6 +3146,7 @@
sDefaults.putBoolean(KEY_USE_USIM_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL, true);
sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false);
+ sDefaults.putString(KEY_SMART_FORWARDING_CONFIG_COMPONENT_NAME_STRING, "");
sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN,
false);
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 918bf60..373c5d2 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -297,8 +297,11 @@
* it could be the current active opportunistic subscription in use, or the
* subscription user selected as default data subscription in DSDS mode.
*
- * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
- * READ_PHONE_STATE}
+ * Requires Permission: No permission is required to listen, but notification requires
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or the calling
+ * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges})
+ * on any active subscription.
+ *
* @see #onActiveDataSubscriptionIdChanged
*/
public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 0x00400000;
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 09046a6..63d427a 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -951,8 +951,7 @@
* @return associated subscription id
*/
public int getSubscriptionId() {
- final int subId = (mSubId == DEFAULT_SUBSCRIPTION_ID)
- ? getDefaultSmsSubscriptionId() : mSubId;
+ final int subId = getSubIdOrDefault();
boolean isSmsSimPickActivityNeeded = false;
final Context context = ActivityThread.currentApplication().getApplicationContext();
try {
@@ -985,6 +984,17 @@
}
/**
+ * @return the subscription ID associated with this {@link SmsManager} or the default set by the
+ * user if this instance was created using {@link SmsManager#getDefault}.
+ *
+ * If there is no default set by the user, this method returns
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+ */
+ private int getSubIdOrDefault() {
+ return (mSubId == DEFAULT_SUBSCRIPTION_ID) ? getDefaultSmsSubscriptionId() : mSubId;
+ }
+
+ /**
* Returns the ISms service, or throws an UnsupportedOperationException if
* the service does not exist.
*/
@@ -1151,8 +1161,9 @@
try {
ISms iSms = getISmsService();
if (iSms != null) {
- success = iSms.enableCellBroadcastForSubscriber(
- getSubscriptionId(), messageIdentifier, ranType);
+ // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+ success = iSms.enableCellBroadcastForSubscriber(getSubIdOrDefault(),
+ messageIdentifier, ranType);
}
} catch (RemoteException ex) {
// ignore it
@@ -1187,8 +1198,9 @@
try {
ISms iSms = getISmsService();
if (iSms != null) {
- success = iSms.disableCellBroadcastForSubscriber(
- getSubscriptionId(), messageIdentifier, ranType);
+ // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+ success = iSms.disableCellBroadcastForSubscriber(getSubIdOrDefault(),
+ messageIdentifier, ranType);
}
} catch (RemoteException ex) {
// ignore it
@@ -1230,7 +1242,8 @@
try {
ISms iSms = getISmsService();
if (iSms != null) {
- success = iSms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
+ // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+ success = iSms.enableCellBroadcastRangeForSubscriber(getSubIdOrDefault(),
startMessageId, endMessageId, ranType);
}
} catch (RemoteException ex) {
@@ -1273,7 +1286,8 @@
try {
ISms iSms = getISmsService();
if (iSms != null) {
- success = iSms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
+ // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+ success = iSms.disableCellBroadcastRangeForSubscriber(getSubIdOrDefault(),
startMessageId, endMessageId, ranType);
}
} catch (RemoteException ex) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ffd5b16..6dd1691 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4845,22 +4845,18 @@
* Registers a listener object to receive notification of changes
* in specified telephony states.
* <p>
- * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony
- * state of interest in the events argument.
+ * To register a listener, pass a {@link PhoneStateListener}
+ * and specify at least one telephony state of interest in
+ * the events argument.
*
- * At registration, and when a specified telephony state changes, the telephony manager invokes
- * the appropriate callback method on the listener object and passes the current (updated)
- * values.
+ * At registration, and when a specified telephony state
+ * changes, the telephony manager invokes the appropriate
+ * callback method on the listener object and passes the
+ * current (updated) values.
* <p>
- * To un-register a listener, pass the listener object and set the events argument to
+ * To unregister a listener, pass the listener object and set the
+ * events argument to
* {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
- *
- * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
- * applies to the given subId. Otherwise, applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
- * pass a separate listener object to each TelephonyManager object created with
- * {@link #createForSubscriptionId}.
- *
* Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
* call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
* {@link SecurityException} will be thrown otherwise.
@@ -4875,18 +4871,17 @@
if (mContext == null) return;
try {
boolean notifyNow = (getITelephony() != null);
+ // If the listener has not explicitly set the subId (for example, created with the
+ // default constructor), replace the subId so it will listen to the account the
+ // telephony manager is created with.
+ if (listener.mSubId == null) {
+ listener.mSubId = mSubId;
+ }
+
ITelephonyRegistry registry = getTelephonyRegistry();
if (registry != null) {
- // listen to the subId the telephony manager is created with. Ignore subId in
- // PhoneStateListener.
- registry.listenForSubscriber(mSubId, getOpPackageName(),
+ registry.listenForSubscriber(listener.mSubId, getOpPackageName(),
listener.callback, events, notifyNow);
- // TODO: remove this once we remove PhoneStateListener constructor with subId.
- if (events == PhoneStateListener.LISTEN_NONE) {
- listener.mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- } else {
- listener.mSubId = mSubId;
- }
} else {
Rlog.w(TAG, "telephony registry not ready.");
}
@@ -10552,6 +10547,9 @@
/**
* Set preferred opportunistic data subscription id.
*
+ * Switch internet data to preferred opportunistic data subscription id. This api
+ * can result in lose of internet connectivity for short period of time while internet data
+ * is handed over.
* <p>Requires that the calling app has carrier privileges on both primary and
* secondary subscriptions (see
* {@link #hasCarrierPrivileges}), or has permission
@@ -10630,9 +10628,11 @@
*
* This api should be called to inform OpportunisticNetwork Service about the availability
* of a network at the current location. This information will be used by OpportunisticNetwork
- * service to decide to attach to the network opportunistically. If an empty list is passed,
+ * service to enable modem stack and to attach to the network. If an empty list is passed,
* it is assumed that no network is available and will result in disabling the modem stack
- * to save power.
+ * to save power. This api do not switch internet data once network attach is completed.
+ * Use {@link TelephonyManager#setPreferredOpportunisticDataSubscription}
+ * to switch internet data after network attach is complete.
* Requires that the calling app has carrier privileges on both primary and
* secondary subscriptions (see {@link #hasCarrierPrivileges}), or has permission
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
@@ -10703,6 +10703,25 @@
}
/**
+ * It indicates whether modem is enabled or not per slot.
+ * It's the corresponding status of {@link #enableModemForSlot}.
+ *
+ * @param slotIndex which slot it's checking.
+ * @hide
+ */
+ public boolean isModemEnabledForSlot(int slotIndex) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isModemEnabledForSlot(slotIndex, mContext.getOpPackageName());
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "enableModem RemoteException", ex);
+ }
+ return false;
+ }
+
+ /**
* Broadcast intent action for network country code changes.
*
* <p>
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 8cdf6a2..cc037e3 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.annotation.WorkerThread;
import android.content.Context;
@@ -38,25 +39,36 @@
import com.android.internal.telephony.ITelephony;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
/**
* Manages IMS provisioning and configuration parameters, as well as callbacks for apps to listen
* to changes in these configurations.
*
- * Note: IMS provisioning keys are defined per carrier or OEM using OMA-DM or other provisioning
- * applications and may vary. For compatibility purposes, the first 100 integer values used in
- * {@link #setProvisioningIntValue(int, int)} have been reserved for existing provisioning keys
- * previously defined in the Android framework. Some common constants have been defined in this
- * class to make integrating with other system apps easier. USE WITH CARE!
+ * IMS provisioning keys are defined per carrier or OEM using OMA-DM or other provisioning
+ * applications and may vary. It is up to the carrier and OEM applications to ensure that the
+ * correct provisioning keys are being used when integrating with a vendor's ImsService.
*
- * To avoid collisions, please use String based configurations when possible:
- * {@link #setProvisioningStringValue(int, String)} and {@link #getProvisioningStringValue(int)}.
+ * Note: For compatibility purposes, the integer values [0 - 99] used in
+ * {@link #setProvisioningIntValue(int, int)} have been reserved for existing provisioning keys
+ * previously defined in the Android framework. Please do not redefine new provisioning keys in this
+ * range or it may generate collisions with existing keys. Some common constants have also been
+ * defined in this class to make integrating with other system apps easier.
* @hide
*/
@SystemApi
public class ProvisioningManager {
+ /**@hide*/
+ @StringDef(prefix = "STRING_QUERY_RESULT_ERROR_", value = {
+ STRING_QUERY_RESULT_ERROR_GENERIC,
+ STRING_QUERY_RESULT_ERROR_NOT_READY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StringResultError {}
+
/**
* The query from {@link #getProvisioningStringValue(int)} has resulted in an unspecified error.
*/
@@ -268,14 +280,13 @@
* This operation is blocking and should not be performed on the UI thread.
*
* @param key A String that represents the provisioning key, which is defined by the OEM.
- * @return a String value for the provided key, {@code null} if the key doesn't exist, or one
- * of the following error codes: {@link #STRING_QUERY_RESULT_ERROR_GENERIC},
- * {@link #STRING_QUERY_RESULT_ERROR_NOT_READY}.
+ * @return a String value for the provided key, {@code null} if the key doesn't exist, or
+ * {@link StringResultError} if there was an error getting the value for the provided key.
* @throws IllegalArgumentException if the key provided was invalid.
*/
@WorkerThread
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public @Nullable String getProvisioningStringValue(int key) {
+ public @Nullable @StringResultError String getProvisioningStringValue(int key) {
try {
return getITelephony().getImsProvisioningString(mSubId, key);
} catch (RemoteException e) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 9e2d9ee..8332ffe 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1958,5 +1958,7 @@
/**
* Get the IRadio HAL Version encoded as 100 * MAJOR_VERSION + MINOR_VERSION or -1 if unknown
*/
- int getRadioHalVersion();
+ int getRadioHalVersion();
+
+ boolean isModemEnabledForSlot(int slotIndex, String callingPackage);
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index d93e582..f5985b4 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -164,6 +164,63 @@
// We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
// revoked.
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ return appOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, uid, callingPackage)
+ == AppOpsManager.MODE_ALLOWED;
+ }
+
+ /**
+ * Check whether the app with the given pid/uid can read phone state, or has carrier
+ * privileges on any active subscription.
+ *
+ * <p>If the app does not have carrier privilege, this method will return {@code false} instead
+ * of throwing a SecurityException. Therefore, the callers cannot tell the difference
+ * between M+ apps which declare the runtime permission but do not have it, and pre-M apps
+ * which declare the static permission but had access revoked via AppOps. Apps in the former
+ * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for
+ * use only if the behavior in both scenarios is meant to be identical.
+ *
+ * @return {@code true} if the app can read phone state or has carrier privilege;
+ * {@code false} otherwise.
+ */
+ public static boolean checkReadPhoneStateOnAnyActiveSub(
+ Context context, int pid, int uid, String callingPackage, String message) {
+ return checkReadPhoneStateOnAnyActiveSub(context, TELEPHONY_SUPPLIER, pid, uid,
+ callingPackage, message);
+ }
+
+ @VisibleForTesting
+ public static boolean checkReadPhoneStateOnAnyActiveSub(
+ Context context, Supplier<ITelephony> telephonySupplier, int pid, int uid,
+ String callingPackage, String message) {
+ try {
+ context.enforcePermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
+
+ // SKIP checking for run-time permission since caller has PRIVILEGED permission
+ return true;
+ } catch (SecurityException privilegedPhoneStateException) {
+ try {
+ context.enforcePermission(
+ android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
+ } catch (SecurityException phoneStateException) {
+ SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ int[] activeSubIds = sm.getActiveSubscriptionIdList();
+ for (int activeSubId : activeSubIds) {
+ // If we don't have the runtime permission, but do have carrier privileges, that
+ // suffices for reading phone state.
+ if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
+ // revoked.
+ AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
return appOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, uid, callingPackage) ==
AppOpsManager.MODE_ALLOWED;
}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index 41cb74a..e36f976 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -17,6 +17,7 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.server.wm.flicker"/>
+ <option name="exclude-annotation" value="org.junit.Ignore" />
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6000s" />
<option name="hidden-api-checks" value="false" />
diff --git a/packages/PackageInstaller/Android.mk b/tests/GamePerformance/Android.mk
similarity index 73%
rename from packages/PackageInstaller/Android.mk
rename to tests/GamePerformance/Android.mk
index ab5483c..58654de 100644
--- a/packages/PackageInstaller/Android.mk
+++ b/tests/GamePerformance/Android.mk
@@ -16,17 +16,24 @@
include $(CLEAR_VARS)
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_PACKAGE_NAME := PackageInstaller
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
+LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
+
+LOCAL_PACKAGE_NAME := GamePerformance
+
LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_STATIC_JAVA_LIBRARIES := xz-java
-LOCAL_STATIC_ANDROID_LIBRARIES := androidx.leanback_leanback
+LOCAL_CERTIFICATE := platform
+
include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/tests/GamePerformance/AndroidManifest.xml b/tests/GamePerformance/AndroidManifest.xml
new file mode 100644
index 0000000..b331e2c
--- /dev/null
+++ b/tests/GamePerformance/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.gameperformance">
+ <uses-sdk android:minSdkVersion="25"/>
+ <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application android:theme="@style/noeffects">
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.gameperformance.GamePerformanceActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!-- self-instrumenting test package. -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="android.gameperformance">
+ </instrumentation>
+</manifest>
diff --git a/tests/GamePerformance/res/values/themes.xml b/tests/GamePerformance/res/values/themes.xml
new file mode 100644
index 0000000..6313071
--- /dev/null
+++ b/tests/GamePerformance/res/values/themes.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<resources>
+ <style name="noeffects" parent="@android:style/Theme.Holo.NoActionBar.Fullscreen">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:fadingEdge">none</item>
+ <item name="android:windowContentTransitions">false</item>
+ <item name="android:windowAnimationStyle">@null</item>
+ </style>
+</resources>
diff --git a/tests/GamePerformance/src/android/gameperformance/ATraceRunner.java b/tests/GamePerformance/src/android/gameperformance/ATraceRunner.java
new file mode 100644
index 0000000..25754fd
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/ATraceRunner.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.gameperformance;
+
+import java.io.BufferedReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import android.app.Instrumentation;
+import android.os.AsyncTask;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+/**
+ * Helper that runs atrace command for required duration and category. Results are read from
+ * the output of atrace and serialized to the provided file. We cannot use direct atrace to
+ * file because atrace is executed in UI automator context and analysis is done in test context.
+ * In last case output file is not accessible from the both contexts.
+ */
+public class ATraceRunner extends AsyncTask<Void, Integer, Boolean>{
+ private final static String TAG = "ATraceRunner";
+
+ // Report that atrace is done.
+ public interface Delegate {
+ public void onProcessed(boolean success);
+ }
+
+ private final Instrumentation mInstrumentation;
+ private final String mOutput;
+ private final int mTimeInSeconds;
+ private final String mCategory;
+ private final Delegate mDelegate;
+
+ public ATraceRunner(Instrumentation instrumentation,
+ String output,
+ int timeInSeconds,
+ String category,
+ Delegate delegate) {
+ mInstrumentation = instrumentation;
+ mOutput = output;
+ mTimeInSeconds = timeInSeconds;
+ mCategory = category;
+ mDelegate = delegate;
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ BufferedReader bufferedReader = null;
+ FileWriter writer = null;
+ try {
+ // Run the command.
+ final String cmd = "atrace -t " + mTimeInSeconds + " " + mCategory;
+ Log.i(TAG, "Running atrace... " + cmd);
+ writer = new FileWriter(mOutput);
+ final ParcelFileDescriptor fd =
+ mInstrumentation.getUiAutomation().executeShellCommand(cmd);
+ bufferedReader = new BufferedReader(
+ new InputStreamReader(new ParcelFileDescriptor.AutoCloseInputStream(fd)));
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ writer.write(line);
+ writer.write("\n");
+ }
+ Log.i(TAG, "Running atrace... DONE");
+ return true;
+ } catch (IOException e) {
+ Log.i(TAG, "atrace failed", e);
+ return false;
+ } finally {
+ Utils.closeQuietly(bufferedReader);
+ Utils.closeQuietly(writer);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ mDelegate.onProcessed(result);
+ }
+
+}
diff --git a/tests/GamePerformance/src/android/gameperformance/CustomOpenGLView.java b/tests/GamePerformance/src/android/gameperformance/CustomOpenGLView.java
new file mode 100644
index 0000000..2b37280
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/CustomOpenGLView.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.gameperformance;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.content.Context;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+
+public class CustomOpenGLView extends GLSurfaceView {
+ private Random mRandom;
+ private List<Long> mFrameTimes;
+
+ public CustomOpenGLView(Context context) {
+ super(context);
+
+ mRandom = new Random();
+ mFrameTimes = new ArrayList<Long>();
+
+ setEGLContextClientVersion(2);
+
+ setRenderer(new GLSurfaceView.Renderer() {
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ gl.glClearDepthf(1.0f);
+ gl.glEnable(GL10.GL_DEPTH_TEST);
+ gl.glDepthFunc(GL10.GL_LEQUAL);
+
+ gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
+ GL10.GL_NICEST); }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ GLES20.glViewport(0, 0, width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ GLES20.glClearColor(
+ mRandom.nextFloat(), mRandom.nextFloat(), mRandom.nextFloat(), 1.0f);
+ gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+ synchronized (mFrameTimes) {
+ mFrameTimes.add(System.currentTimeMillis());
+ }
+ }
+ });
+ setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
+ }
+
+ /**
+ * Resets frame times in order to calculate fps for different test pass.
+ */
+ public void resetFrameTimes() {
+ synchronized (mFrameTimes) {
+ mFrameTimes.clear();
+ }
+ }
+
+ /**
+ * Returns current fps based on collected frame times.
+ */
+ public double getFps() {
+ synchronized (mFrameTimes) {
+ if (mFrameTimes.size() < 2) {
+ return 0.0f;
+ }
+ return 1000.0 * mFrameTimes.size() /
+ (mFrameTimes.get(mFrameTimes.size() - 1) - mFrameTimes.get(0));
+ }
+ }
+}
diff --git a/tests/GamePerformance/src/android/gameperformance/CustomSurfaceView.java b/tests/GamePerformance/src/android/gameperformance/CustomSurfaceView.java
new file mode 100644
index 0000000..a46668d
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/CustomSurfaceView.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.gameperformance;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Trace;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+/**
+ * Minimal SurfaceView that sends buffer on request.
+ */
+public class CustomSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+ // Tag for trace when buffer is requested.
+ public final static String LOCAL_REQUEST_BUFFER = "localRequestBuffer";
+ // Tag for trace when buffer is posted.
+ public final static String LOCAL_POST_BUFFER = "localPostBuffer";
+
+ private final Object mSurfaceLock = new Object();
+ // Keeps frame times. Used to calculate fps.
+ private List<Long> mFrameTimes;
+ // Surface to send.
+ private Surface mSurface;
+ private Handler mHandler;
+
+ private Runnable mInvalidateSurfaceTask = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mSurfaceLock) {
+ if (mSurface == null) {
+ return;
+ }
+ invalidateSurface(true, true);
+ mHandler.post(this);
+ }
+ }
+ };
+
+ public CustomSurfaceView(Context context) {
+ super(context);
+ mFrameTimes = new ArrayList<Long>();
+ getHolder().addCallback(this);
+ getHolder().setFormat(PixelFormat.OPAQUE);
+
+ HandlerThread thread = new HandlerThread("SurfaceInvalidator");
+ thread.start();
+ mHandler = new Handler(thread.getLooper());
+ }
+
+ /**
+ * Resets frame times in order to calculate fps for different test pass.
+ */
+ public void resetFrameTimes() {
+ synchronized (mSurfaceLock) {
+ mFrameTimes.clear();
+ }
+ }
+
+ /**
+ * Returns current fps based on collected frame times.
+ */
+ public double getFps() {
+ synchronized (mSurfaceLock) {
+ if (mFrameTimes.size() < 2) {
+ return 0.0f;
+ }
+ return 1000.0 * mFrameTimes.size() /
+ (mFrameTimes.get(mFrameTimes.size() - 1) - mFrameTimes.get(0));
+ }
+ }
+
+ /**
+ * Invalidates surface.
+ * @param traceCalls set to true in case we need register trace calls. Not used for warm-up.
+ * @param drawFps perform drawing current fps on surface to have some payload on surface.
+ */
+ public void invalidateSurface(boolean traceCalls, boolean drawFps) {
+ synchronized (mSurfaceLock) {
+ if (mSurface == null) {
+ throw new IllegalStateException("Surface is not ready");
+ }
+ if (traceCalls) {
+ Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, LOCAL_REQUEST_BUFFER);
+ }
+ Canvas canvas = mSurface.lockHardwareCanvas();
+ if (traceCalls) {
+ Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+ }
+
+ if (drawFps) {
+ int textSize = canvas.getHeight() / 24;
+ Paint paint = new Paint();
+ paint.setTextSize(textSize);
+ paint.setColor(0xFFFF8040);
+ canvas.drawARGB(92, 255, 255, 255);
+ canvas.drawText("FPS: " + String.format("%.2f", getFps()), 10, 300, paint);
+ }
+
+ if (traceCalls) {
+ Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, LOCAL_POST_BUFFER);
+ }
+ mSurface.unlockCanvasAndPost(canvas);
+ if (traceCalls) {
+ Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+ }
+
+ mFrameTimes.add(System.currentTimeMillis());
+ }
+ }
+
+ /**
+ * Wait until surface is created and ready to use or return immediately if surface
+ * already exists.
+ */
+ public void waitForSurfaceReady() {
+ synchronized (mSurfaceLock) {
+ if (mSurface == null) {
+ try {
+ mSurfaceLock.wait(5000);
+ } catch(InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ if (mSurface == null)
+ throw new IllegalStateException("Surface is not ready.");
+ }
+ }
+
+ /**
+ * Waits until surface is destroyed or return immediately if surface does not exist.
+ */
+ public void waitForSurfaceDestroyed() {
+ synchronized (mSurfaceLock) {
+ if (mSurface != null) {
+ try {
+ mSurfaceLock.wait(5000);
+ } catch(InterruptedException e) {
+ }
+ }
+ if (mSurface != null)
+ throw new IllegalStateException("Surface still exists.");
+ }
+ }
+
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ // This method is always called at least once, after surfaceCreated.
+ synchronized (mSurfaceLock) {
+ mSurface = holder.getSurface();
+ mSurfaceLock.notify();
+ mHandler.post(mInvalidateSurfaceTask);
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ synchronized (mSurfaceLock) {
+ mHandler.removeCallbacks(mInvalidateSurfaceTask);
+ mSurface = null;
+ mSurfaceLock.notify();
+ }
+ }
+}
diff --git a/tests/GamePerformance/src/android/gameperformance/GamePerformanceActivity.java b/tests/GamePerformance/src/android/gameperformance/GamePerformanceActivity.java
new file mode 100644
index 0000000..b0e6196
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/GamePerformanceActivity.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.gameperformance;
+
+import java.util.concurrent.CountDownLatch;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.RelativeLayout;
+
+/**
+ * Minimal activity that holds SurfaceView or GLSurfaceView.
+ * call attachSurfaceView or attachOpenGLView to switch views.
+ */
+public class GamePerformanceActivity extends Activity {
+ private CustomSurfaceView mSurfaceView = null;
+ private CustomOpenGLView mOpenGLView = null;
+ private RelativeLayout mRootLayout;
+
+ public void attachSurfaceView() throws InterruptedException {
+ synchronized (mRootLayout) {
+ if (mSurfaceView != null) {
+ return;
+ }
+ final CountDownLatch latch = new CountDownLatch(1);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (mOpenGLView != null) {
+ mRootLayout.removeView(mOpenGLView);
+ mOpenGLView = null;
+ }
+ mSurfaceView = new CustomSurfaceView(GamePerformanceActivity.this);
+ mRootLayout.addView(mSurfaceView);
+ latch.countDown();
+ }
+ });
+ latch.await();
+ mSurfaceView.waitForSurfaceReady();
+ }
+ }
+
+ public void attachOpenGLView() throws InterruptedException {
+ synchronized (mRootLayout) {
+ if (mOpenGLView != null) {
+ return;
+ }
+ final CountDownLatch latch = new CountDownLatch(1);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (mSurfaceView != null) {
+ mRootLayout.removeView(mSurfaceView);
+ mSurfaceView = null;
+ }
+ mOpenGLView = new CustomOpenGLView(GamePerformanceActivity.this);
+ mRootLayout.addView(mOpenGLView);
+ latch.countDown();
+ }
+ });
+ latch.await();
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ // To layouts in parent. First contains list of Surfaces and second
+ // controls. Controls stay on top.
+ mRootLayout = new RelativeLayout(this);
+ mRootLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ Rect rect = new Rect();
+ getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
+
+ mOpenGLView = new CustomOpenGLView(this);
+ mRootLayout.addView(mOpenGLView);
+
+ setContentView(mRootLayout);
+ }
+
+ public void resetFrameTimes() {
+ if (mSurfaceView != null) {
+ mSurfaceView.resetFrameTimes();
+ } else if (mOpenGLView != null) {
+ mOpenGLView.resetFrameTimes();
+ } else {
+ throw new IllegalStateException("Nothing attached");
+ }
+ }
+
+ public double getFps() {
+ if (mSurfaceView != null) {
+ return mSurfaceView.getFps();
+ } else if (mOpenGLView != null) {
+ return mOpenGLView.getFps();
+ } else {
+ throw new IllegalStateException("Nothing attached");
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+}
\ No newline at end of file
diff --git a/tests/GamePerformance/src/android/gameperformance/GamePerformanceTest.java b/tests/GamePerformance/src/android/gameperformance/GamePerformanceTest.java
new file mode 100644
index 0000000..e5de7d7
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/GamePerformanceTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.gameperformance;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Trace;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+public class GamePerformanceTest extends
+ ActivityInstrumentationTestCase2<GamePerformanceActivity> {
+ private final static String TAG = "GamePerformanceTest";
+
+ private final static int GRAPHIC_BUFFER_WARMUP_LOOP_CNT = 60;
+
+ public GamePerformanceTest() {
+ super(GamePerformanceActivity.class);
+ }
+
+ @SmallTest
+ public void testGraphicBufferMetrics() throws IOException, InterruptedException {
+ Bundle status = new Bundle();
+
+ for (int i = 0; i < 2; ++i) {
+ if (i == 0) {
+ getActivity().attachSurfaceView();
+ } else {
+ getActivity().attachOpenGLView();
+ }
+
+ // Perform warm-up.
+ Thread.sleep(2000);
+
+ // Once atrace is done, this one is triggered.
+ CountDownLatch latch = new CountDownLatch(1);
+
+ final String passTag = i == 0 ? "surface" : "opengl";
+ final String output = (new File(getInstrumentation().getContext().getFilesDir(),
+ "atrace_" + passTag + ".log")).getAbsolutePath();
+ Log.i(TAG, "Collecting traces to " + output);
+ new ATraceRunner(getInstrumentation(), output, 5, "gfx", new ATraceRunner.Delegate() {
+ @Override
+ public void onProcessed(boolean success) {
+ latch.countDown();
+ }
+ }).execute();
+
+ // Reset frame times and perform invalidation loop while atrace is running.
+ getActivity().resetFrameTimes();
+ latch.await();
+
+ // Copy results.
+ final Map<String, Double> metrics =
+ GraphicBufferMetrics.processGraphicBufferResult(output, passTag);
+ for (Map.Entry<String, Double> metric : metrics.entrySet()) {
+ status.putDouble(metric.getKey(), metric.getValue());
+ }
+ // Also record FPS.
+ status.putDouble(passTag + "_fps", getActivity().getFps());
+ }
+
+ getInstrumentation().sendStatus(Activity.RESULT_OK, status);
+ }
+}
diff --git a/tests/GamePerformance/src/android/gameperformance/GraphicBufferMetrics.java b/tests/GamePerformance/src/android/gameperformance/GraphicBufferMetrics.java
new file mode 100644
index 0000000..dffce1a
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/GraphicBufferMetrics.java
@@ -0,0 +1,530 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.gameperformance;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * Utility class that performs analysis of atrace logs. This is implemented without Android
+ * dependencies and therefore can be used in stand-alone mode.
+ * Idea of this is to track atrace gfx event from graphics buffer producer/consumer.
+ * We analyze here from surfaceflinger
+ * queueBuffer - event when buffer was queued.
+ * acquireBuffer - event when buffer was requested for composition.
+ * releaseBuffer - even when buffer was released after composition.
+ * This also track events, issued locally
+ * localPostBuffer - event when buffer was posted from the local app.
+ *
+ * queueBuffer, acquireBuffer, releaseBuffer is accompanied with buffer name so we
+ * can track life-cycle of particular buffer.
+ * We don't have such information for localPostBuffer, however we can track next queueBuffer
+ * from surfaceflinger corresponds to previous localPostBuffer.
+ *
+ * Following results are calculated:
+ * post_time_[min/max/avr]_mcs - time for localPostBuffer duration.
+ * ready_time_[min/max/avr]_mcs - time from localPostBuffer to when buffer was acquired by
+ * surfaceflinger.
+ * latency_[min/max/avr]_mcs - time from localPostBuffer to when buffer was released by
+ * surfaceflinger.
+ * missed_frame_percents - percentage of missed frames (frames that do not have right sequence
+ * of events).
+ *
+ * Following is example of atrace logs from different platforms
+ * <...>-5237 (-----) [000] ...1 228.380392: tracing_mark_write: B|11|SurfaceView - android.gameperformance/android.gameperformance.GamePerformanceActivity#0: 2
+ * surfaceflinger-5855 ( 5855) [001] ...1 169.627364: tracing_mark_write: B|24|acquireBuffer
+ * HwBinder:617_2-652 ( 617) [002] d..1 360262.921756: sde_evtlog: 617|sde_encoder_virt_atomic_check:855|19|0|0|0|0|0|0|0|0|0|0|0|0|0|0
+ */
+public class GraphicBufferMetrics {
+ private final static String TAG = "GraphicBufferMetrics";
+
+ private final static String KEY_POST_TIME = "post_time";
+ private final static String KEY_READY_TIME = "ready_time";
+ private final static String KEY_LATENCY = "latency";
+ private final static String SUFFIX_MIN = "min";
+ private final static String SUFFIX_MAX = "max";
+ private final static String SUFFIX_MEDIAN = "median";
+ private final static String KEY_MISSED_FRAME_RATE = "missed_frame_percents";
+
+ private final static int EVENT_POST_BUFFER = 0;
+ private final static int EVENT_QUEUE_BUFFER = 1;
+ private final static int EVENT_ACQUIRE_BUFFER = 2;
+ private final static int EVENT_RELEASE_BUFFER = 3;
+
+ // atrace prints this line. Used as a marker to make sure that we can parse its output.
+ private final static String ATRACE_HEADER =
+ "# TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION";
+
+ private final static String[] KNOWN_PHRASES = new String[] {
+ "capturing trace... done", "TRACE:"};
+ private final static List<String> KNWON_PHRASES_LIST = Arrays.asList(KNOWN_PHRASES);
+
+ // Type of the atrace event we can parse and analyze.
+ private final static String FUNCTION_TRACING_MARK_WRITE = "tracing_mark_write";
+
+ // Trace event we can ignore. It contains current timestamp information for the atrace output.
+ private final static String TRACE_EVENT_CLOCK_SYNC = "trace_event_clock_sync:";
+
+ // Threshold we consider test passes successfully. If we cannot collect enough amount of frames
+ // let fail the test. 50 is calculated 10 frames per second running for five seconds.
+ private final static int MINIMAL_SAMPLE_CNT_TO_PASS = 50;
+
+ /**
+ * Raw event in atrace. Stored hierarchically.
+ */
+ private static class RawEvent {
+ // Parent of this event or null for the root holder.
+ public final RawEvent mParent;
+ // Time of the event in mcs.
+ public final long mTime;
+ // Duration of the event in mcs.
+ public long mDuration;
+ // Name/body of the event.
+ public final String mName;
+ // Children events.
+ public final List<RawEvent> mChildren;
+
+ public RawEvent(RawEvent parent, long time, String name) {
+ mParent = parent;
+ mTime = time;
+ mName = name;
+ mDuration = -1;
+ mChildren = new ArrayList<>();
+ }
+
+ /**
+ * Recursively finds child events.
+ * @param path specify path to events. For example a/b. That means to find child with name
+ * 'a' of the current event and in this child find child with name 'b'. Path
+ * can consist from only one segment and that means we analyze only children of
+ * the current event.
+ * @param collector to collect found events.
+ */
+ public void findEvents(String path, List<RawEvent> collector) {
+ final int separator = path.indexOf('/');
+ final String current = separator > 0 ? path.substring(0, separator) : path;
+ final String nextPath = separator > 0 ? path.substring(separator + 1) : null;
+ for (RawEvent child : mChildren) {
+ if (child.mName.equals(current)) {
+ if (nextPath != null) {
+ child.findEvents(nextPath, collector);
+ } else {
+ collector.add(child);
+ }
+ }
+ }
+ }
+
+ public void dump(String prefix) {
+ System.err.print(prefix);
+ System.err.println(mTime + "[" + mDuration + "] " + mName);
+ for (RawEvent e : mChildren) {
+ e.dump(prefix + " ");
+ }
+ }
+ }
+
+ /**
+ * Describes graphic buffer event. local post, queued, acquired, released.
+ */
+ private static class BufferEvent {
+ public final int mType;
+ public final long mTime;
+ public final long mDuration;
+ public final String mBufferId;
+
+ public BufferEvent(int type, long time, long duration, String bufferId) {
+ mType = type;
+ mTime = time;
+ mDuration = duration;
+ mBufferId = bufferId;
+ }
+
+ @Override
+ public String toString() {
+ return "Type: " + mType + ". Time: " + mTime +
+ "[" + mDuration + "]. Buffer: " + mBufferId + ".";
+ }
+ }
+
+ /**
+ * Returns true if given char is digit.
+ */
+ private static boolean isDigitChar(char c) {
+ return (c >= '0') && (c <= '9');
+ }
+
+ /**
+ * Returns true if given char is digit or '.'.
+ */
+ private static boolean isDoubleDigitChar(char c) {
+ return (c == '.') || isDigitChar(c);
+ }
+
+ /**
+ * Convert timestamp string that represents double value in seconds to long time that represents
+ * timestamp in microseconds.
+ */
+ private static long getTimeStamp(String timeStampStr) {
+ return (long)(1000000.0 * Double.parseDouble(timeStampStr));
+ }
+
+ /**
+ * Reads atrace log and build event model. Result is a map, where key specifies event for the
+ * particular thread. Value is the synthetic root RawEvent that holds all events for the
+ * thread. Events are stored hierarchically.
+ */
+ private static Map<Integer, RawEvent> buildEventModel(String fileName) throws IOException {
+ Map<Integer, RawEvent> result = new HashMap<>();
+
+ BufferedReader bufferedReader = null;
+ String line = "";
+ boolean headerDetected = false;
+ try {
+ bufferedReader = new BufferedReader(new FileReader(fileName));
+ while ((line = bufferedReader.readLine()) != null) {
+ // Make sure we find comment that describes output format we can with.
+ headerDetected |= line.equals(ATRACE_HEADER);
+ // Skip comments.
+ if (line.startsWith("#")) {
+ continue;
+ }
+ // Skip known service output
+ if (KNWON_PHRASES_LIST.contains(line)) {
+ continue;
+ }
+
+ if (!headerDetected) {
+ // We don't know the format of this line.
+ throw new IllegalStateException("Header was not detected");
+ }
+
+ // TASK-PID in header exists at position 12. PID position 17 should contains first
+ // digit of thread id after the '-'.
+ if (!isDigitChar(line.charAt(17)) || line.charAt(16) != '-') {
+ throw new IllegalStateException("Failed to parse thread id: " + line);
+ }
+ int rightIndex = line.indexOf(' ', 17);
+ final String threadIdStr = line.substring(17, rightIndex);
+ final int threadId = Integer.parseInt(threadIdStr);
+
+ // TIMESTAMP in header exists at position 45
+ // This position should point in the middle of timestamp which is ended by ':'.
+ int leftIndex = 45;
+ while (isDoubleDigitChar(line.charAt(leftIndex))) {
+ --leftIndex;
+ }
+ rightIndex = line.indexOf(':', 45);
+
+ final String timeStampString = line.substring(leftIndex + 1, rightIndex);
+ final long timeStampMcs = getTimeStamp(timeStampString);
+
+ // Find function name, pointed by FUNCTION. Long timestamp can shift if position
+ // so use end of timestamp to find the function which is ended by ':'.
+ leftIndex = rightIndex + 1;
+ while (Character.isWhitespace(line.charAt(leftIndex))) {
+ ++leftIndex;
+ }
+ rightIndex = line.indexOf(':', leftIndex);
+ final String function = line.substring(leftIndex, rightIndex);
+
+ if (!function.equals(FUNCTION_TRACING_MARK_WRITE)) {
+ continue;
+ }
+
+ // Rest of the line is event body.
+ leftIndex = rightIndex + 1;
+ while (Character.isWhitespace(line.charAt(leftIndex))) {
+ ++leftIndex;
+ }
+
+ final String event = line.substring(leftIndex);
+ if (event.startsWith(TRACE_EVENT_CLOCK_SYNC)) {
+ continue;
+ }
+
+ // Parse event, for example:
+ // B|615|SurfaceView - android.gameperformance.GamePerformanceActivity#0: 1
+ // E|615
+ // C|11253|operation id|2
+ StringTokenizer eventTokenizer = new StringTokenizer(event, "|");
+ final String eventType = eventTokenizer.nextToken();
+
+ // Attach root on demand.
+ if (!result.containsKey(threadId)) {
+ result.put(threadId, new RawEvent(null /* parent */,
+ timeStampMcs,
+ "#ROOT_" + threadId));
+ }
+
+ switch (eventType) {
+ case "B": {
+ // Log entry starts.
+ eventTokenizer.nextToken(); // PID
+ String eventText = eventTokenizer.nextToken();
+ while (eventTokenizer.hasMoreTokens()) {
+ eventText += " ";
+ eventText += eventTokenizer.nextToken();
+ }
+ RawEvent parent = result.get(threadId);
+ RawEvent current = new RawEvent(parent, timeStampMcs, eventText);
+ parent.mChildren.add(current);
+ result.put(threadId, current);
+ }
+ break;
+ case "E": {
+ // Log entry ends.
+ RawEvent current = result.get(threadId);
+ current.mDuration = timeStampMcs - current.mTime;
+ if (current.mParent == null) {
+ // Detect a tail of the previous call. Remove last child element if it
+ // exists once it does not belong to the root.
+ if (!current.mChildren.isEmpty()) {
+ current.mChildren.remove(current.mChildren.size() -1);
+ }
+ } else {
+ result.put(threadId, current.mParent);
+ }
+ }
+ break;
+ case "C":
+ // Counter, ignore
+ break;
+ default:
+ throw new IllegalStateException(
+ "Unrecognized trace: " + line + " # " + eventType + " # " + event);
+ }
+ }
+
+ // Detect incomplete events and detach from the root.
+ Set<Integer> threadIds = new TreeSet<>();
+ threadIds.addAll(result.keySet());
+ for (int threadId : threadIds) {
+ RawEvent root = result.get(threadId);
+ if (root.mParent == null) {
+ // Last trace was closed.
+ continue;
+ }
+ // Find the root.
+ while (root.mParent != null) {
+ root = root.mParent;
+ }
+ // Discard latest incomplete element.
+ root.mChildren.remove(root.mChildren.size() - 1);
+ result.put(threadId, root);
+ }
+ } catch (Exception e) {
+ throw new IOException("Failed to process " + line, e);
+ } finally {
+ Utils.closeQuietly(bufferedReader);
+ }
+
+ return result;
+ }
+
+ /**
+ * Processes provided atrace log and calculates graphics buffer metrics.
+ * @param fileName name of atrace log file.
+ * @param testTag tag to separate results for the different passes.
+ */
+ public static Map<String, Double> processGraphicBufferResult(
+ String fileName, String testTag) throws IOException {
+ final Map<Integer, RawEvent> model = buildEventModel(fileName);
+
+ List<RawEvent> collectorPostBuffer = new ArrayList<>();
+ List<RawEvent> collectorQueueBuffer = new ArrayList<>();
+ List<RawEvent> collectorReleaseBuffer = new ArrayList<>();
+ List<RawEvent> collectorAcquireBuffer = new ArrayList<>();
+
+ // Collect required events.
+ for (RawEvent root : model.values()) {
+ // Surface view
+ root.findEvents("localPostBuffer", collectorPostBuffer);
+ // OpengGL view
+ root.findEvents("eglSwapBuffersWithDamageKHR", collectorPostBuffer);
+
+ root.findEvents("queueBuffer", collectorQueueBuffer);
+ root.findEvents("onMessageReceived/handleMessageInvalidate/latchBuffer/" +
+ "updateTexImage/acquireBuffer",
+ collectorAcquireBuffer);
+ // PI stack
+ root.findEvents(
+ "onMessageReceived/handleMessageRefresh/postComposition/releaseBuffer",
+ collectorReleaseBuffer);
+ // NYC stack
+ root.findEvents(
+ "onMessageReceived/handleMessageRefresh/releaseBuffer",
+ collectorReleaseBuffer);
+ }
+
+ // Convert raw event to buffer events.
+ List<BufferEvent> bufferEvents = new ArrayList<>();
+ for (RawEvent event : collectorPostBuffer) {
+ bufferEvents.add(
+ new BufferEvent(EVENT_POST_BUFFER, event.mTime, event.mDuration, null));
+ }
+ toBufferEvents(EVENT_QUEUE_BUFFER, collectorQueueBuffer, bufferEvents);
+ toBufferEvents(EVENT_ACQUIRE_BUFFER, collectorAcquireBuffer, bufferEvents);
+ toBufferEvents(EVENT_RELEASE_BUFFER, collectorReleaseBuffer, bufferEvents);
+
+ // Sort events based on time. These events are originally taken from different threads so
+ // order is not always preserved.
+ Collections.sort(bufferEvents, new Comparator<BufferEvent>() {
+ @Override
+ public int compare(BufferEvent o1, BufferEvent o2) {
+ if (o1.mTime < o2.mTime) {
+ return -1;
+ } if (o1.mTime > o2.mTime) {
+ return +1;
+ } else {
+ return 0;
+ }
+ }
+ });
+
+ // Collect samples.
+ List<Long> postTimes = new ArrayList<>();
+ List<Long> readyTimes = new ArrayList<>();
+ List<Long> latencyTimes = new ArrayList<>();
+ long missedCnt = 0;
+
+ for (int i = 0; i < bufferEvents.size(); ++i) {
+ if (bufferEvents.get(i).mType != EVENT_POST_BUFFER) {
+ continue;
+ }
+ final int queueIndex = findNextOfType(bufferEvents, i + 1, EVENT_QUEUE_BUFFER);
+ if (queueIndex < 0) {
+ break;
+ }
+ final int acquireIndex = findNextOfBufferId(bufferEvents, queueIndex + 1,
+ bufferEvents.get(queueIndex).mBufferId);
+ if (acquireIndex < 0) {
+ break;
+ }
+ if (bufferEvents.get(acquireIndex).mType != EVENT_ACQUIRE_BUFFER) {
+ // Was not actually presented.
+ ++missedCnt;
+ continue;
+ }
+ final int releaseIndex = findNextOfBufferId(bufferEvents, acquireIndex + 1,
+ bufferEvents.get(queueIndex).mBufferId);
+ if (releaseIndex < 0) {
+ break;
+ }
+ if (bufferEvents.get(releaseIndex).mType != EVENT_RELEASE_BUFFER) {
+ // Was not actually presented.
+ ++missedCnt;
+ continue;
+ }
+
+ postTimes.add(bufferEvents.get(i).mDuration);
+ readyTimes.add(
+ bufferEvents.get(acquireIndex).mTime - bufferEvents.get(i).mTime);
+ latencyTimes.add(
+ bufferEvents.get(releaseIndex).mTime - bufferEvents.get(i).mTime);
+ }
+
+ if (postTimes.size() < MINIMAL_SAMPLE_CNT_TO_PASS) {
+ throw new IllegalStateException("Too few sample cnt: " + postTimes.size() +". " +
+ MINIMAL_SAMPLE_CNT_TO_PASS + " is required.");
+ }
+
+ Map<String, Double> status = new TreeMap<>();
+ addResults(status, testTag, KEY_POST_TIME, postTimes);
+ addResults(status, testTag, KEY_READY_TIME, readyTimes);
+ addResults(status, testTag, KEY_LATENCY, latencyTimes);
+ status.put(testTag + "_" + KEY_MISSED_FRAME_RATE,
+ 100.0 * missedCnt / (missedCnt + postTimes.size()));
+ return status;
+ }
+
+ private static void addResults(
+ Map<String, Double> status, String tag, String key, List<Long> times) {
+ Collections.sort(times);
+ long min = times.get(0);
+ long max = times.get(0);
+ for (long time : times) {
+ min = Math.min(min, time);
+ max = Math.max(max, time);
+ }
+ status.put(tag + "_" + key + "_" + SUFFIX_MIN, (double)min);
+ status.put(tag + "_" + key + "_" + SUFFIX_MAX, (double)max);
+ status.put(tag + "_" + key + "_" + SUFFIX_MEDIAN, (double)times.get(times.size() / 2));
+ }
+
+ // Helper to convert surface flinger events to buffer events.
+ private static void toBufferEvents(
+ int type, List<RawEvent> rawEvents, List<BufferEvent> bufferEvents) {
+ for (RawEvent event : rawEvents) {
+ if (event.mChildren.isEmpty()) {
+ throw new IllegalStateException("Buffer name is expected");
+ }
+ final String bufferName = event.mChildren.get(0).mName;
+ if (bufferName.startsWith("SurfaceView - android.gameperformance")) {
+ bufferEvents.add(
+ new BufferEvent(type, event.mTime, event.mDuration, bufferName));
+ }
+ }
+ }
+
+ private static int findNextOfType(List<BufferEvent> events, int startIndex, int type) {
+ for (int i = startIndex; i < events.size(); ++i) {
+ if (events.get(i).mType == type) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private static int findNextOfBufferId(
+ List<BufferEvent> events, int startIndex, String bufferId) {
+ for (int i = startIndex; i < events.size(); ++i) {
+ if (bufferId.equals(events.get(i).mBufferId)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public static void main(String[] args) {
+ if (args.length != 1) {
+ System.err.println("Usage: " + TAG + " atrace.log");
+ return;
+ }
+
+ try {
+ System.out.println("Results:");
+ for (Map.Entry<?, ?> entry :
+ processGraphicBufferResult(args[0], "default").entrySet()) {
+ System.out.println(" " + entry.getKey() + " = " + entry.getValue());
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/tests/GamePerformance/src/android/gameperformance/Utils.java b/tests/GamePerformance/src/android/gameperformance/Utils.java
new file mode 100644
index 0000000..6481971
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/Utils.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.gameperformance;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+public class Utils {
+ public static void closeQuietly(Closeable closeable) {
+ try {
+ if (closeable != null) {
+ closeable.close();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b35de59..0ead228 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -104,6 +104,7 @@
import android.net.ConnectivityManager.PacketKeepaliveCallback;
import android.net.ConnectivityManager.TooManyRequestsException;
import android.net.ConnectivityThread;
+import android.net.IDnsResolver;
import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
@@ -240,6 +241,7 @@
private static final String CLAT_PREFIX = "v4-";
private static final String MOBILE_IFNAME = "test_rmnet_data0";
private static final String WIFI_IFNAME = "test_wlan0";
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
private MockContext mServiceContext;
private WrappedConnectivityService mService;
@@ -256,6 +258,7 @@
@Mock INetworkManagementService mNetworkManagementService;
@Mock INetworkStatsService mStatsService;
@Mock INetworkPolicyManager mNpm;
+ @Mock IDnsResolver mMockDnsResolver;
@Mock INetd mMockNetd;
@Mock NetworkStackClient mNetworkStack;
@@ -1053,8 +1056,8 @@
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
- IpConnectivityLog log, INetd netd) {
- super(context, netManager, statsService, policyManager, log);
+ IpConnectivityLog log, INetd netd, IDnsResolver dnsResolver) {
+ super(context, netManager, statsService, policyManager, dnsResolver, log);
mNetd = netd;
mLingerDelayMs = TEST_LINGER_DELAY_MS;
}
@@ -1218,7 +1221,8 @@
mStatsService,
mNpm,
mock(IpConnectivityLog.class),
- mMockNetd);
+ mMockNetd,
+ mMockDnsResolver);
final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
ArgumentCaptor.forClass(INetworkPolicyListener.class);
@@ -4777,14 +4781,14 @@
ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
// Clear any interactions that occur as a result of CS starting up.
- reset(mNetworkManagementService);
+ reset(mMockDnsResolver);
- final String[] EMPTY_STRING_ARRAY = new String[0];
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
waitForIdle();
- verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
- anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
- verifyNoMoreInteractions(mNetworkManagementService);
+ verify(mMockDnsResolver, never()).setResolverConfiguration(
+ anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
+ eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+ verifyNoMoreInteractions(mMockDnsResolver);
final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -4801,28 +4805,29 @@
mCellNetworkAgent.connect(false);
waitForIdle();
// CS tells netd about the empty DNS config for this network.
- verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
- anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
- reset(mNetworkManagementService);
+ verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
+ anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
+ eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+ reset(mMockDnsResolver);
cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
mCellNetworkAgent.sendLinkProperties(cellLp);
waitForIdle();
- verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+ verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
anyInt(), mStringArrayCaptor.capture(), any(), any(),
- eq(""), tlsServers.capture());
+ eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
assertEquals(1, mStringArrayCaptor.getValue().length);
assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1"));
// Opportunistic mode.
assertTrue(ArrayUtils.contains(tlsServers.getValue(), "2001:db8::1"));
- reset(mNetworkManagementService);
+ reset(mMockDnsResolver);
cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
mCellNetworkAgent.sendLinkProperties(cellLp);
waitForIdle();
- verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+ verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
anyInt(), mStringArrayCaptor.capture(), any(), any(),
- eq(""), tlsServers.capture());
+ eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
assertEquals(2, mStringArrayCaptor.getValue().length);
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
@@ -4830,7 +4835,7 @@
assertEquals(2, tlsServers.getValue().length);
assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mNetworkManagementService);
+ reset(mMockDnsResolver);
final String TLS_SPECIFIER = "tls.example.com";
final String TLS_SERVER6 = "2001:db8:53::53";
@@ -4840,22 +4845,21 @@
new PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS).toParcel());
waitForIdle();
- verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+ verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
anyInt(), mStringArrayCaptor.capture(), any(), any(),
- eq(TLS_SPECIFIER), eq(TLS_SERVERS));
+ eq(TLS_SPECIFIER), eq(TLS_SERVERS), eq(EMPTY_STRING_ARRAY));
assertEquals(2, mStringArrayCaptor.getValue().length);
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mNetworkManagementService);
+ reset(mMockDnsResolver);
}
@Test
public void testPrivateDnsSettingsChange() throws Exception {
- final String[] EMPTY_STRING_ARRAY = new String[0];
ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
// Clear any interactions that occur as a result of CS starting up.
- reset(mNetworkManagementService);
+ reset(mMockDnsResolver);
// The default on Android is opportunistic mode ("Automatic").
setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
@@ -4868,9 +4872,10 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
waitForIdle();
// CS tells netd about the empty DNS config for this network.
- verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
- anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
- verifyNoMoreInteractions(mNetworkManagementService);
+ verify(mMockDnsResolver, never()).setResolverConfiguration(
+ anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
+ eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+ verifyNoMoreInteractions(mMockDnsResolver);
final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -4889,9 +4894,9 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(false);
waitForIdle();
- verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+ verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
anyInt(), mStringArrayCaptor.capture(), any(), any(),
- eq(""), tlsServers.capture());
+ eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
assertEquals(2, mStringArrayCaptor.getValue().length);
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
@@ -4899,7 +4904,7 @@
assertEquals(2, tlsServers.getValue().length);
assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mNetworkManagementService);
+ reset(mMockDnsResolver);
cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
mCellNetworkAgent);
@@ -4911,26 +4916,26 @@
assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
- verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
+ verify(mMockDnsResolver, times(1)).setResolverConfiguration(
anyInt(), mStringArrayCaptor.capture(), any(), any(),
- eq(""), eq(EMPTY_STRING_ARRAY));
+ eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
assertEquals(2, mStringArrayCaptor.getValue().length);
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mNetworkManagementService);
+ reset(mMockDnsResolver);
cellNetworkCallback.assertNoCallback();
setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
- verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+ verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
anyInt(), mStringArrayCaptor.capture(), any(), any(),
- eq(""), tlsServers.capture());
+ eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
assertEquals(2, mStringArrayCaptor.getValue().length);
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
assertEquals(2, tlsServers.getValue().length);
assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mNetworkManagementService);
+ reset(mMockDnsResolver);
cellNetworkCallback.assertNoCallback();
setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
@@ -5761,6 +5766,7 @@
cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
reset(mNetworkManagementService);
+ reset(mMockDnsResolver);
when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
.thenReturn(getClatInterfaceConfig(myIpv4));
@@ -5768,7 +5774,7 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(true);
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
+ verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
// Switching default network updates TCP buffer sizes.
verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
@@ -5778,17 +5784,22 @@
cellLp.addLinkAddress(myIpv4);
mCellNetworkAgent.sendLinkProperties(cellLp);
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- verify(mMockNetd, times(1)).resolverStopPrefix64Discovery(cellNetId);
+ verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
+ verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
+ eq(cellNetId), eq(EMPTY_STRING_ARRAY), any(), any(),
+ eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
verifyNoMoreInteractions(mMockNetd);
+ verifyNoMoreInteractions(mMockDnsResolver);
reset(mMockNetd);
+ reset(mMockDnsResolver);
// Remove IPv4 address. Expect prefix discovery to be started again.
cellLp.removeLinkAddress(myIpv4);
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
mCellNetworkAgent.sendLinkProperties(cellLp);
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
+ verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
// When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
@@ -5818,6 +5829,12 @@
assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
+ verify(mMockDnsResolver, times(1)).setResolverConfiguration(
+ eq(cellNetId), mStringArrayCaptor.capture(), any(), any(),
+ eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+ assertEquals(1, mStringArrayCaptor.getValue().length);
+ assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "8.8.8.8"));
+
// Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
// linkproperties are cleaned up.
cellLp.addLinkAddress(myIpv4);
@@ -5825,7 +5842,7 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- verify(mMockNetd, times(1)).resolverStopPrefix64Discovery(cellNetId);
+ verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
// As soon as stop is called, the linkproperties lose the stacked interface.
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
@@ -5840,7 +5857,9 @@
networkCallback.assertNoCallback();
verifyNoMoreInteractions(mMockNetd);
+ verifyNoMoreInteractions(mMockDnsResolver);
reset(mMockNetd);
+ reset(mMockDnsResolver);
// Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
@@ -5854,7 +5873,7 @@
cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
mCellNetworkAgent.sendLinkProperties(cellLp);
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
+ verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
kNat64PrefixString, 96);
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
@@ -5937,6 +5956,7 @@
// Disconnect cell
reset(mNetworkManagementService);
+ reset(mMockNetd);
mCellNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
// LOST callback is triggered earlier than removing idle timer. Broadcast should also be
@@ -5944,8 +5964,9 @@
// unexpectedly before network being removed.
waitForIdle();
verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
- verify(mNetworkManagementService, times(1)).removeNetwork(
- eq(mCellNetworkAgent.getNetwork().netId));
+ verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
+ verify(mMockDnsResolver, times(1))
+ .clearResolverConfiguration(eq(mCellNetworkAgent.getNetwork().netId));
// Disconnect wifi
ConditionVariable cv = waitForConnectivityBroadcasts(1);
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 15ba43d..8fa0ab9 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -29,13 +29,13 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.IDnsResolver;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.RouteInfo;
import android.net.shared.PrivateDnsConfig;
-import android.os.INetworkManagementService;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
@@ -73,7 +73,7 @@
MockContentResolver mContentResolver;
@Mock Context mCtx;
- @Mock INetworkManagementService mNMService;
+ @Mock IDnsResolver mMockDnsResolver;
@Mock MockableSystemProperties mSystemProperties;
@Before
@@ -83,7 +83,7 @@
mContentResolver.addProvider(Settings.AUTHORITY,
new FakeSettingsProvider());
when(mCtx.getContentResolver()).thenReturn(mContentResolver);
- mDnsManager = new DnsManager(mCtx, mNMService, mSystemProperties);
+ mDnsManager = new DnsManager(mCtx, mMockDnsResolver, mSystemProperties);
// Clear the private DNS settings
Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "");
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 6de4aa1..142769f 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -32,6 +32,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.IDnsResolver;
import android.net.INetd;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -69,6 +70,7 @@
LingerMonitor mMonitor;
@Mock ConnectivityService mConnService;
+ @Mock IDnsResolver mDnsResolver;
@Mock INetd mNetd;
@Mock INetworkManagementService mNMS;
@Mock Context mCtx;
@@ -353,7 +355,7 @@
caps.addCapability(0);
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
- caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS,
+ caps, 50, mCtx, null, mMisc, mConnService, mNetd, mDnsResolver, mNMS,
NetworkFactory.SerialNumber.NONE);
nai.everValidated = true;
return nai;
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index cc09fb7..b709af1 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.when;
import android.net.ConnectivityManager;
+import android.net.IDnsResolver;
import android.net.INetd;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
@@ -63,6 +64,7 @@
@Mock ConnectivityService mConnectivity;
@Mock NetworkMisc mMisc;
+ @Mock IDnsResolver mDnsResolver;
@Mock INetd mNetd;
@Mock INetworkManagementService mNms;
@Mock InterfaceConfiguration mConfig;
@@ -72,7 +74,7 @@
Handler mHandler;
Nat464Xlat makeNat464Xlat() {
- return new Nat464Xlat(mNai, mNetd, mNms) {
+ return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) {
@Override protected int getNetId() {
return NETID;
}
@@ -205,7 +207,7 @@
verify(mNms).unregisterObserver(eq(nat));
assertTrue(c.getValue().getStackedLinks().isEmpty());
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+ verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
assertIdle(nat);
// Stacked interface removed notification arrives and is ignored.
@@ -331,7 +333,7 @@
verify(mNetd).clatdStop(eq(BASE_IFACE));
verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
verify(mNms).unregisterObserver(eq(nat));
- verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+ verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
assertTrue(c.getValue().getStackedLinks().isEmpty());
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
assertIdle(nat);
@@ -358,7 +360,7 @@
verify(mNetd).clatdStop(eq(BASE_IFACE));
verify(mNms).unregisterObserver(eq(nat));
- verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+ verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
assertIdle(nat);
// In-flight interface up notification arrives: no-op
@@ -390,7 +392,7 @@
verify(mNetd).clatdStop(eq(BASE_IFACE));
verify(mNms).unregisterObserver(eq(nat));
- verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+ verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
assertIdle(nat);
verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 9eab4be..d28ab70 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -31,6 +31,8 @@
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
@@ -80,6 +82,7 @@
@Mock private MockableSystemProperties mSystemProperties;
@Mock private Resources mResources;
@Mock private SharedLog mLog;
+ @Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;
// Like so many Android system APIs, these cannot be mocked because it is marked final.
// We have to use the real versions.
@@ -109,7 +112,6 @@
public class WrappedEntitlementManager extends EntitlementManager {
public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
- public boolean everRunUiEntitlement = false;
public int uiProvisionCount = 0;
public int silentProvisionCount = 0;
@@ -118,20 +120,22 @@
super(ctx, target, log, what, systemProperties);
}
- @Override
- protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
- everRunUiEntitlement = true;
- receiver.send(fakeEntitlementResult, null);
+ public void reset() {
+ fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+ uiProvisionCount = 0;
+ silentProvisionCount = 0;
}
@Override
- protected void runUiTetherProvisioning(int type) {
+ protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
uiProvisionCount++;
+ receiver.send(fakeEntitlementResult, null);
}
@Override
protected void runSilentTetherProvisioning(int type) {
silentProvisionCount++;
+ addDownstreamMapping(type, fakeEntitlementResult);
}
}
@@ -157,6 +161,7 @@
mSM = new TestStateMachine();
mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE,
mSystemProperties);
+ mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
mEnMgr.updateConfiguration(
new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
}
@@ -246,7 +251,6 @@
final CountDownLatch mCallbacklatch = new CountDownLatch(1);
// 1. Entitlement check is not required.
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
- mEnMgr.everRunUiEntitlement = false;
ResultReceiver receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -257,13 +261,13 @@
mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
- assertFalse(mEnMgr.everRunUiEntitlement);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ mEnMgr.reset();
setupForRequiredProvisioning();
mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
INVALID_SUBSCRIPTION_ID));
// 2. No cache value and don't need to run entitlement check.
- mEnMgr.everRunUiEntitlement = false;
receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -274,10 +278,10 @@
mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
- assertFalse(mEnMgr.everRunUiEntitlement);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ mEnMgr.reset();
// 3. No cache value and ui entitlement check is needed.
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
- mEnMgr.everRunUiEntitlement = false;
receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -288,10 +292,10 @@
mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
- assertTrue(mEnMgr.everRunUiEntitlement);
+ assertEquals(1, mEnMgr.uiProvisionCount);
+ mEnMgr.reset();
// 4. Cache value is TETHER_ERROR_PROVISION_FAILED and don't need to run entitlement check.
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
- mEnMgr.everRunUiEntitlement = false;
receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -302,10 +306,10 @@
mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
- assertFalse(mEnMgr.everRunUiEntitlement);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ mEnMgr.reset();
// 5. Cache value is TETHER_ERROR_PROVISION_FAILED and ui entitlement check is needed.
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
- mEnMgr.everRunUiEntitlement = false;
receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -316,10 +320,10 @@
mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
- assertTrue(mEnMgr.everRunUiEntitlement);
+ assertEquals(1, mEnMgr.uiProvisionCount);
+ mEnMgr.reset();
// 6. Cache value is TETHER_ERROR_NO_ERROR.
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
- mEnMgr.everRunUiEntitlement = false;
receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -330,9 +334,9 @@
mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
- assertFalse(mEnMgr.everRunUiEntitlement);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ mEnMgr.reset();
// 7. Test get value for other downstream type.
- mEnMgr.everRunUiEntitlement = false;
receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -343,7 +347,8 @@
mEnMgr.getLatestTetheringEntitlementResult(TETHERING_USB, receiver, false);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
- assertFalse(mEnMgr.everRunUiEntitlement);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ mEnMgr.reset();
}
void callbackTimeoutHelper(final CountDownLatch latch) throws Exception {
@@ -358,15 +363,15 @@
mEnMgr.notifyUpstream(true);
mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
INVALID_SUBSCRIPTION_ID));
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
- mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
mLooper.dispatchAll();
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
- mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_NO_ERROR);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
}
@@ -376,17 +381,17 @@
mEnMgr.notifyUpstream(true);
mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
INVALID_SUBSCRIPTION_ID));
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
- mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
mLooper.dispatchAll();
- mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
mLooper.dispatchAll();
- mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
}
@@ -396,14 +401,14 @@
mEnMgr.notifyUpstream(true);
mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
INVALID_SUBSCRIPTION_ID));
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
- mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_NO_ERROR);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
mLooper.dispatchAll();
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
mLooper.dispatchAll();
- mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
mLooper.dispatchAll();
@@ -417,48 +422,71 @@
mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
INVALID_SUBSCRIPTION_ID));
// 1. start ui provisioning, upstream is mobile
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
mLooper.dispatchAll();
- assertTrue(mEnMgr.uiProvisionCount == 1);
- assertTrue(mEnMgr.silentProvisionCount == 0);
- mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
+ assertEquals(1, mEnMgr.uiProvisionCount);
+ assertEquals(0, mEnMgr.silentProvisionCount);
+ assertTrue(mEnMgr.isCellularUpstreamPermitted());
+ mEnMgr.reset();
// 2. start no-ui provisioning
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false);
mLooper.dispatchAll();
- assertTrue(mEnMgr.silentProvisionCount == 1);
- assertTrue(mEnMgr.uiProvisionCount == 1);
- mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ assertEquals(1, mEnMgr.silentProvisionCount);
+ assertTrue(mEnMgr.isCellularUpstreamPermitted());
+ mEnMgr.reset();
// 3. tear down mobile, then start ui provisioning
mEnMgr.notifyUpstream(false);
mLooper.dispatchAll();
mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
mLooper.dispatchAll();
- assertTrue(mEnMgr.uiProvisionCount == 1);
- assertTrue(mEnMgr.silentProvisionCount == 1);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ assertEquals(0, mEnMgr.silentProvisionCount);
+ mEnMgr.reset();
// 4. switch upstream back to mobile
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
- assertTrue(mEnMgr.uiProvisionCount == 2);
- assertTrue(mEnMgr.silentProvisionCount == 1);
- mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
+ assertEquals(1, mEnMgr.uiProvisionCount);
+ assertEquals(0, mEnMgr.silentProvisionCount);
+ assertTrue(mEnMgr.isCellularUpstreamPermitted());
+ mEnMgr.reset();
// 5. tear down mobile, then switch SIM
mEnMgr.notifyUpstream(false);
mLooper.dispatchAll();
mEnMgr.reevaluateSimCardProvisioning();
- assertTrue(mEnMgr.uiProvisionCount == 2);
- assertTrue(mEnMgr.silentProvisionCount == 1);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ assertEquals(0, mEnMgr.silentProvisionCount);
+ mEnMgr.reset();
// 6. switch upstream back to mobile again
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
- assertTrue(mEnMgr.uiProvisionCount == 2);
- assertTrue(mEnMgr.silentProvisionCount == 4);
- mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
- mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
- mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ assertEquals(3, mEnMgr.silentProvisionCount);
+ mEnMgr.reset();
}
+ @Test
+ public void testCallStopTetheringWhenUiProvisioningFail() {
+ setupForRequiredProvisioning();
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
+ INVALID_SUBSCRIPTION_ID));
+ verify(mEntitlementFailedListener, times(0)).onUiEntitlementFailed(TETHERING_WIFI);
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+ mEnMgr.notifyUpstream(true);
+ mLooper.dispatchAll();
+ mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+ mLooper.dispatchAll();
+ assertEquals(1, mEnMgr.uiProvisionCount);
+ verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI);
+ }
+
+
public class TestStateMachine extends StateMachine {
public final ArrayList<Message> messages = new ArrayList<>();
private final State
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index e17fb47..92f1ddb 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -2314,7 +2314,7 @@
int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
IDiagnostics* diag) {
ManifestExtractor extractor(apk, options);
- return extractor.Dump(printer, diag);
+ return extractor.Dump(printer, diag) ? 0 : 1;
}
} // namespace aapt
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 78967e4..be227e7 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2190,22 +2190,7 @@
key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
}
} else {
- if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
- key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
- } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
- allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
- key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
- } else if (wepKeys[0] != null) {
- key = SSID + "WEP";
- } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
- key = SSID + KeyMgmt.strings[KeyMgmt.OWE];
- } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
- key = SSID + KeyMgmt.strings[KeyMgmt.SAE];
- } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
- key = SSID + KeyMgmt.strings[KeyMgmt.SUITE_B_192];
- } else {
- key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
- }
+ key = getSsidAndSecurityTypeString();
if (!shared) {
key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
}
@@ -2215,6 +2200,30 @@
}
/** @hide
+ * return the SSID + security type in String format.
+ */
+ public String getSsidAndSecurityTypeString() {
+ String key;
+ if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+ } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
+ || allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ } else if (wepKeys[0] != null) {
+ key = SSID + "WEP";
+ } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.OWE];
+ } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.SAE];
+ } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.SUITE_B_192];
+ } else {
+ key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
+ }
+ return key;
+ }
+
+ /** @hide
* get configKey, force calculating the config string
*/
public String configKey() {
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index d927052..ba9fc78 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -348,4 +348,47 @@
}
assertTrue(exceptionThrown);
}
+
+ /**
+ * Verifies that getSsidAndSecurityTypeString returns the correct String for networks of
+ * various different security types
+ */
+ @Test
+ public void testGetSsidAndSecurityTypeString() {
+ WifiConfiguration config = new WifiConfiguration();
+ final String mSsid = "TestAP";
+ config.SSID = mSsid;
+
+ // Test various combinations
+ config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WPA_PSK],
+ config.getSsidAndSecurityTypeString());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WPA_EAP],
+ config.getSsidAndSecurityTypeString());
+
+ config.wepKeys[0] = "TestWep";
+ config.allowedKeyManagement.clear();
+ assertEquals(mSsid + "WEP", config.getSsidAndSecurityTypeString());
+
+ config.wepKeys[0] = null;
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.OWE);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getSsidAndSecurityTypeString());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.SAE);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SAE], config.getSsidAndSecurityTypeString());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SUITE_B_192],
+ config.getSsidAndSecurityTypeString());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getSsidAndSecurityTypeString());
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 600abc9..fa17db1 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1382,4 +1382,60 @@
r.run();
}
}
+
+ /**
+ * Test behavior of isEnhancedOpenSupported
+ * @throws Exception
+ */
+ @Test
+ public void testIsEnhancedOpenSupported() throws Exception {
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(WifiManager.WIFI_FEATURE_OWE));
+ assertTrue(mWifiManager.isEnhancedOpenSupported());
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(~WifiManager.WIFI_FEATURE_OWE));
+ assertFalse(mWifiManager.isEnhancedOpenSupported());
+ }
+
+ /**
+ * Test behavior of isWpa3SaeSupported
+ * @throws Exception
+ */
+ @Test
+ public void testIsWpa3SaeSupported() throws Exception {
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(WifiManager.WIFI_FEATURE_WPA3_SAE));
+ assertTrue(mWifiManager.isWpa3SaeSupported());
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(~WifiManager.WIFI_FEATURE_WPA3_SAE));
+ assertFalse(mWifiManager.isWpa3SaeSupported());
+ }
+
+ /**
+ * Test behavior of isWpa3SuiteBSupported
+ * @throws Exception
+ */
+ @Test
+ public void testIsWpa3SuiteBSupported() throws Exception {
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(WifiManager.WIFI_FEATURE_WPA3_SUITE_B));
+ assertTrue(mWifiManager.isWpa3SuiteBSupported());
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(~WifiManager.WIFI_FEATURE_WPA3_SUITE_B));
+ assertFalse(mWifiManager.isWpa3SuiteBSupported());
+ }
+
+ /**
+ * Test behavior of isEasyConnectSupported
+ * @throws Exception
+ */
+ @Test
+ public void testIsEasyConnectSupported() throws Exception {
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(WifiManager.WIFI_FEATURE_DPP));
+ assertTrue(mWifiManager.isEasyConnectSupported());
+ when(mWifiService.getSupportedFeatures())
+ .thenReturn(new Long(~WifiManager.WIFI_FEATURE_DPP));
+ assertFalse(mWifiManager.isEasyConnectSupported());
+ }
}