Merge "Destroy drawing cache when switching layer type" into nyc-dev
diff --git a/Android.mk b/Android.mk
index ae5d67e..2017404 100644
--- a/Android.mk
+++ b/Android.mk
@@ -442,8 +442,6 @@
telephony/java/com/android/internal/telephony/ISms.aidl \
telephony/java/com/android/internal/telephony/ISub.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
- telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl \
- telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl \
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index 429674c..c1dbce7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4480,6 +4480,7 @@
method public void startActivity(android.content.Intent, android.os.Bundle);
method public void startActivityForResult(android.content.Intent, int);
method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+ method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public void unregisterForContextMenu(android.view.View);
}
@@ -4571,6 +4572,7 @@
method public void onRequestPermissionsFromFragment(android.app.Fragment, java.lang.String[], int);
method public boolean onShouldSaveFragmentState(android.app.Fragment);
method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+ method public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public boolean onUseFragmentManagerInflaterFactory();
}
@@ -5897,11 +5899,11 @@
method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
- method public java.lang.String getLongSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
- method public java.lang.String getOrganizationName(android.content.ComponentName);
+ method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -5920,7 +5922,7 @@
method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
- method public java.lang.String getShortSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5971,12 +5973,12 @@
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
- method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
- method public void setOrganizationName(android.content.ComponentName, java.lang.String);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -5999,7 +6001,7 @@
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
- method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -6313,6 +6315,8 @@
method public static final long getMinimumPeriod();
method public int getNetworkType();
method public android.content.ComponentName getService();
+ method public long getTriggerContentMaxDelay();
+ method public long getTriggerContentUpdateDelay();
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
method public boolean isPeriodic();
method public boolean isPersisted();
@@ -6343,6 +6347,8 @@
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
+ method public android.app.job.JobInfo.Builder setTriggerContentMaxDelay(long);
+ method public android.app.job.JobInfo.Builder setTriggerContentUpdateDelay(long);
}
public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
@@ -8615,6 +8621,7 @@
field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+ field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
@@ -8709,6 +8716,7 @@
field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
@@ -9497,11 +9505,8 @@
public class LauncherApps {
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
- method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
- method public int getShortcutIconResId(android.content.pm.ShortcutInfo);
- method public int getShortcutIconResId(java.lang.String, java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
@@ -10042,7 +10047,9 @@
public final class ShortcutInfo implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
+ method public java.util.List<java.lang.String> getCategories();
method public android.os.PersistableBundle getExtras();
+ method public int getIconResourceId();
method public java.lang.String getId();
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
@@ -10066,12 +10073,14 @@
field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
field public static final int FLAG_PINNED = 2; // 0x2
+ field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
}
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context);
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName);
+ method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.List<java.lang.String>);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
@@ -10082,15 +10091,15 @@
}
public class ShortcutManager {
- method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
- method public void deleteAllDynamicShortcuts();
- method public void deleteDynamicShortcut(java.lang.String);
+ method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
method public long getRateLimitResetTime();
method public int getRemainingCallCount();
+ method public void removeAllDynamicShortcuts();
+ method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
}
@@ -14436,13 +14445,13 @@
public final class OutputConfiguration implements android.os.Parcelable {
ctor public OutputConfiguration(android.view.Surface);
+ ctor public OutputConfiguration(int, android.view.Surface);
method public int describeContents();
method public android.view.Surface getSurface();
- method public int getSurfaceSetId();
- method public void setSurfaceSetId(int);
+ method public int getSurfaceGroupId();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
- field public static final int SURFACE_SET_ID_INVALID = -1; // 0xffffffff
+ field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
}
public final class RggbChannelVector {
@@ -22966,6 +22975,7 @@
method public android.content.Intent createSettingsIntent();
method public android.content.Intent createSetupIntent();
method public int describeContents();
+ method public android.os.Bundle getExtras();
method public java.lang.String getId();
method public java.lang.String getParentId();
method public android.content.pm.ServiceInfo getServiceInfo();
@@ -22995,6 +23005,7 @@
ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
+ method public android.media.tv.TvInputInfo.Builder setExtras(android.os.Bundle);
method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
}
@@ -29584,6 +29595,7 @@
public class StorageManager {
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryStorageVolume();
+ method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index befff23..9a39b4c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -217,6 +217,7 @@
field public static final java.lang.String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES";
field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR";
field public static final java.lang.String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
+ field public static final java.lang.String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
field public static final java.lang.String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
@@ -4613,6 +4614,7 @@
method public void startActivity(android.content.Intent, android.os.Bundle);
method public void startActivityForResult(android.content.Intent, int);
method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+ method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public void unregisterForContextMenu(android.view.View);
}
@@ -4704,6 +4706,7 @@
method public void onRequestPermissionsFromFragment(android.app.Fragment, java.lang.String[], int);
method public boolean onShouldSaveFragmentState(android.app.Fragment);
method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+ method public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public boolean onUseFragmentManagerInflaterFactory();
}
@@ -6040,11 +6043,11 @@
method public java.lang.String getDeviceOwnerNameOnAnyUser();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
- method public java.lang.String getLongSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
- method public java.lang.String getOrganizationName(android.content.ComponentName);
+ method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -6067,7 +6070,7 @@
method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
- method public java.lang.String getShortSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -6121,12 +6124,12 @@
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
- method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
- method public void setOrganizationName(android.content.ComponentName, java.lang.String);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -6149,7 +6152,7 @@
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
- method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -6581,6 +6584,8 @@
method public static final long getMinimumPeriod();
method public int getNetworkType();
method public android.content.ComponentName getService();
+ method public long getTriggerContentMaxDelay();
+ method public long getTriggerContentUpdateDelay();
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
method public boolean isPeriodic();
method public boolean isPersisted();
@@ -6611,6 +6616,8 @@
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
+ method public android.app.job.JobInfo.Builder setTriggerContentMaxDelay(long);
+ method public android.app.job.JobInfo.Builder setTriggerContentUpdateDelay(long);
}
public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
@@ -8934,6 +8941,7 @@
field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+ field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
@@ -9835,11 +9843,8 @@
public class LauncherApps {
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
- method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
- method public int getShortcutIconResId(android.content.pm.ShortcutInfo);
- method public int getShortcutIconResId(java.lang.String, java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
@@ -10442,7 +10447,9 @@
public final class ShortcutInfo implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
+ method public java.util.List<java.lang.String> getCategories();
method public android.os.PersistableBundle getExtras();
+ method public int getIconResourceId();
method public java.lang.String getId();
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
@@ -10466,12 +10473,14 @@
field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
field public static final int FLAG_PINNED = 2; // 0x2
+ field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
}
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context);
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName);
+ method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.List<java.lang.String>);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
@@ -10482,15 +10491,15 @@
}
public class ShortcutManager {
- method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
- method public void deleteAllDynamicShortcuts();
- method public void deleteDynamicShortcut(java.lang.String);
+ method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
method public long getRateLimitResetTime();
method public int getRemainingCallCount();
+ method public void removeAllDynamicShortcuts();
+ method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
}
@@ -14844,20 +14853,20 @@
public final class OutputConfiguration implements android.os.Parcelable {
ctor public OutputConfiguration(android.view.Surface);
+ ctor public OutputConfiguration(int, android.view.Surface);
ctor public OutputConfiguration(android.view.Surface, int);
- ctor public OutputConfiguration(android.hardware.camera2.params.OutputConfiguration);
+ ctor public OutputConfiguration(int, android.view.Surface, int);
method public int describeContents();
method public int getRotation();
method public android.view.Surface getSurface();
- method public int getSurfaceSetId();
- method public void setSurfaceSetId(int);
+ method public int getSurfaceGroupId();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
field public static final int ROTATION_0 = 0; // 0x0
field public static final int ROTATION_180 = 2; // 0x2
field public static final int ROTATION_270 = 3; // 0x3
field public static final int ROTATION_90 = 1; // 0x1
- field public static final int SURFACE_SET_ID_INVALID = -1; // 0xffffffff
+ field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
}
public final class RggbChannelVector {
@@ -24623,6 +24632,7 @@
method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
+ method public android.os.Bundle getExtras();
method public android.hardware.hdmi.HdmiDeviceInfo getHdmiDeviceInfo();
method public java.lang.String getId();
method public java.lang.String getParentId();
@@ -24656,6 +24666,7 @@
ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
+ method public android.media.tv.TvInputInfo.Builder setExtras(android.os.Bundle);
method public android.media.tv.TvInputInfo.Builder setHdmiDeviceInfo(android.hardware.hdmi.HdmiDeviceInfo);
method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon, int);
@@ -31890,6 +31901,7 @@
public class StorageManager {
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryStorageVolume();
+ method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index d39e0b7..6895d48 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4480,6 +4480,7 @@
method public void startActivity(android.content.Intent, android.os.Bundle);
method public void startActivityForResult(android.content.Intent, int);
method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+ method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public void unregisterForContextMenu(android.view.View);
}
@@ -4571,6 +4572,7 @@
method public void onRequestPermissionsFromFragment(android.app.Fragment, java.lang.String[], int);
method public boolean onShouldSaveFragmentState(android.app.Fragment);
method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+ method public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public boolean onUseFragmentManagerInflaterFactory();
}
@@ -5901,11 +5903,11 @@
method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
- method public java.lang.String getLongSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
- method public java.lang.String getOrganizationName(android.content.ComponentName);
+ method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -5924,7 +5926,7 @@
method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
- method public java.lang.String getShortSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5975,12 +5977,12 @@
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
- method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
- method public void setOrganizationName(android.content.ComponentName, java.lang.String);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -6003,7 +6005,7 @@
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
- method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -6317,6 +6319,8 @@
method public static final long getMinimumPeriod();
method public int getNetworkType();
method public android.content.ComponentName getService();
+ method public long getTriggerContentMaxDelay();
+ method public long getTriggerContentUpdateDelay();
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
method public boolean isPeriodic();
method public boolean isPersisted();
@@ -6347,6 +6351,8 @@
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
+ method public android.app.job.JobInfo.Builder setTriggerContentMaxDelay(long);
+ method public android.app.job.JobInfo.Builder setTriggerContentUpdateDelay(long);
}
public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
@@ -8622,6 +8628,7 @@
field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+ field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
@@ -8716,6 +8723,7 @@
field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
@@ -9507,11 +9515,8 @@
public class LauncherApps {
ctor public LauncherApps(android.content.Context);
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
- method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
- method public int getShortcutIconResId(android.content.pm.ShortcutInfo);
- method public int getShortcutIconResId(java.lang.String, java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
@@ -10053,7 +10058,9 @@
public final class ShortcutInfo implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
+ method public java.util.List<java.lang.String> getCategories();
method public android.os.PersistableBundle getExtras();
+ method public int getIconResourceId();
method public java.lang.String getId();
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
@@ -10077,12 +10084,14 @@
field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
field public static final int FLAG_PINNED = 2; // 0x2
+ field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
}
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context);
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName);
+ method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.List<java.lang.String>);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
@@ -10094,15 +10103,15 @@
public class ShortcutManager {
ctor public ShortcutManager(android.content.Context);
- method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
- method public void deleteAllDynamicShortcuts();
- method public void deleteDynamicShortcut(java.lang.String);
+ method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
method public long getRateLimitResetTime();
method public int getRemainingCallCount();
+ method public void removeAllDynamicShortcuts();
+ method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
}
@@ -14448,13 +14457,13 @@
public final class OutputConfiguration implements android.os.Parcelable {
ctor public OutputConfiguration(android.view.Surface);
+ ctor public OutputConfiguration(int, android.view.Surface);
method public int describeContents();
method public android.view.Surface getSurface();
- method public int getSurfaceSetId();
- method public void setSurfaceSetId(int);
+ method public int getSurfaceGroupId();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
- field public static final int SURFACE_SET_ID_INVALID = -1; // 0xffffffff
+ field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
}
public final class RggbChannelVector {
@@ -23034,6 +23043,7 @@
method public android.content.Intent createSettingsIntent();
method public android.content.Intent createSetupIntent();
method public int describeContents();
+ method public android.os.Bundle getExtras();
method public java.lang.String getId();
method public java.lang.String getParentId();
method public android.content.pm.ServiceInfo getServiceInfo();
@@ -23063,6 +23073,7 @@
ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
+ method public android.media.tv.TvInputInfo.Builder setExtras(android.os.Bundle);
method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
}
@@ -29653,6 +29664,7 @@
public class StorageManager {
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryStorageVolume();
+ method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 3385a17..e788d27 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -16,6 +16,9 @@
package android.animation;
+import android.app.ActivityThread;
+import android.app.Application;
+import android.os.Build;
import android.util.ArrayMap;
import android.util.Log;
@@ -133,10 +136,25 @@
// The total duration of finishing all the Animators in the set.
private long mTotalDuration = 0;
+ // In pre-N releases, calling end() before start() on an animator set is no-op. But that is not
+ // consistent with the behavior for other animator types. In order to keep the behavior
+ // consistent within Animation framework, when end() is called without start(), we will start
+ // the animator set and immediately end it for N and forward.
+ private final boolean mShouldIgnoreEndWithoutStart;
+
public AnimatorSet() {
super();
mNodeMap.put(mDelayAnim, mRootNode);
mNodes.add(mRootNode);
+ // Set the flag to ignore calling end() without start() for pre-N releases
+ Application app = ActivityThread.currentApplication();
+ if (app == null || app.getApplicationInfo() == null) {
+ mShouldIgnoreEndWithoutStart = true;
+ } else if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+ mShouldIgnoreEndWithoutStart = true;
+ } else {
+ mShouldIgnoreEndWithoutStart = false;
+ }
}
/**
@@ -365,6 +383,9 @@
*/
@Override
public void end() {
+ if (mShouldIgnoreEndWithoutStart && !isStarted()) {
+ return;
+ }
mTerminated = true;
if (isStarted()) {
endRemainingAnimations();
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index c6a5152..31035a7 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1200,13 +1200,17 @@
boolean animateBasedOnTime(long currentTime) {
boolean done = false;
if (mRunning) {
- final float fraction = getScaledDuration() > 0 ?
- (float)(currentTime - mStartTime) / getScaledDuration() : 1f;
+ final long scaledDuration = getScaledDuration();
+ final float fraction = scaledDuration > 0 ?
+ (float)(currentTime - mStartTime) / scaledDuration : 1f;
final float lastFraction = mOverallFraction;
final boolean newIteration = (int) fraction > (int) lastFraction;
final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
(mRepeatCount != INFINITE);
- if (newIteration && !lastIterationFinished) {
+ if (scaledDuration == 0) {
+ // 0 duration animator, ignore the repeat count and skip to the end
+ done = true;
+ } else if (newIteration && !lastIterationFinished) {
// Time to repeat
if (mListeners != null) {
int numListeners = mListeners.size();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7652766..f7884a7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4405,8 +4405,8 @@
@Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
Bundle options) throws IntentSender.SendIntentException {
if (mParent == null) {
- startIntentSenderForResultInner(intent, requestCode, fillInIntent,
- flagsMask, flagsValues, this, options);
+ startIntentSenderForResultInner(intent, mEmbeddedID, requestCode, fillInIntent,
+ flagsMask, flagsValues, options);
} else if (options != null) {
mParent.startIntentSenderFromChild(this, intent, requestCode,
fillInIntent, flagsMask, flagsValues, extraFlags, options);
@@ -4418,8 +4418,8 @@
}
}
- private void startIntentSenderForResultInner(IntentSender intent, int requestCode,
- Intent fillInIntent, int flagsMask, int flagsValues, Activity activity,
+ private void startIntentSenderForResultInner(IntentSender intent, String who, int requestCode,
+ Intent fillInIntent, int flagsMask, int flagsValues,
Bundle options)
throws IntentSender.SendIntentException {
try {
@@ -4431,7 +4431,7 @@
}
int result = ActivityManagerNative.getDefault()
.startActivityIntentSender(mMainThread.getApplicationThread(), intent,
- fillInIntent, resolvedType, mToken, activity.mEmbeddedID,
+ fillInIntent, resolvedType, mToken, who,
requestCode, flagsMask, flagsValues, options);
if (result == ActivityManager.START_CANCELED) {
throw new IntentSender.SendIntentException();
@@ -4888,8 +4888,23 @@
int requestCode, Intent fillInIntent, int flagsMask, int flagsValues,
int extraFlags, @Nullable Bundle options)
throws IntentSender.SendIntentException {
- startIntentSenderForResultInner(intent, requestCode, fillInIntent,
- flagsMask, flagsValues, child, options);
+ startIntentSenderForResultInner(intent, child.mEmbeddedID, requestCode, fillInIntent,
+ flagsMask, flagsValues, options);
+ }
+
+ /**
+ * Like {@link #startIntentSenderFromChild}, but taking a Fragment; see
+ * {@link #startIntentSenderForResult(IntentSender, int, Intent, int, int, int)}
+ * for more information.
+ *
+ * @hide
+ */
+ public void startIntentSenderFromChildFragment(Fragment child, IntentSender intent,
+ int requestCode, Intent fillInIntent, int flagsMask, int flagsValues,
+ int extraFlags, @Nullable Bundle options)
+ throws IntentSender.SendIntentException {
+ startIntentSenderForResultInner(intent, child.mWho, requestCode, fillInIntent,
+ flagsMask, flagsValues, options);
}
/**
@@ -7035,6 +7050,19 @@
}
@Override
+ public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent,
+ int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
+ int extraFlags, Bundle options) throws IntentSender.SendIntentException {
+ if (mParent == null) {
+ startIntentSenderForResultInner(intent, fragment.mWho, requestCode, fillInIntent,
+ flagsMask, flagsValues, options);
+ } else if (options != null) {
+ mParent.startIntentSenderFromChildFragment(fragment, intent, requestCode,
+ fillInIntent, flagsMask, flagsValues, extraFlags, options);
+ }
+ }
+
+ @Override
public void onRequestPermissionsFromFragment(Fragment fragment, String[] permissions,
int requestCode) {
String who = REQUEST_PERMISSIONS_WHO_PREFIX + fragment.mWho;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d1f5143..631a129 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Matrix;
@@ -1305,6 +1306,12 @@
*/
public boolean isDockable;
+ /**
+ * The resize mode of the task. See {@link ActivityInfo#resizeMode}.
+ * @hide
+ */
+ public int resizeMode;
+
public RecentTaskInfo() {
}
@@ -1349,6 +1356,7 @@
dest.writeInt(0);
}
dest.writeInt(isDockable ? 1 : 0);
+ dest.writeInt(resizeMode);
}
public void readFromParcel(Parcel source) {
@@ -1372,6 +1380,7 @@
bounds = source.readInt() > 0 ?
Rect.CREATOR.createFromParcel(source) : null;
isDockable = source.readInt() == 1;
+ resizeMode = source.readInt();
}
public static final Creator<RecentTaskInfo> CREATOR
@@ -1560,6 +1569,12 @@
*/
public boolean isDockable;
+ /**
+ * The resize mode of the task. See {@link ActivityInfo#resizeMode}.
+ * @hide
+ */
+ public int resizeMode;
+
public RunningTaskInfo() {
}
@@ -1583,6 +1598,7 @@
dest.writeInt(numActivities);
dest.writeInt(numRunning);
dest.writeInt(isDockable ? 1 : 0);
+ dest.writeInt(resizeMode);
}
public void readFromParcel(Parcel source) {
@@ -1599,6 +1615,7 @@
numActivities = source.readInt();
numRunning = source.readInt();
isDockable = source.readInt() != 0;
+ resizeMode = source.readInt();
}
public static final Creator<RunningTaskInfo> CREATOR = new Creator<RunningTaskInfo>() {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index ed590e6..bf56f25 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1921,6 +1921,16 @@
}
@Override
+ public void deleteApplicationCacheFilesAsUser(String packageName, int userId,
+ IPackageDataObserver observer) {
+ try {
+ mPM.deleteApplicationCacheFilesAsUser(packageName, userId, observer);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
public void freeStorageAndNotify(String volumeUuid, long idealStorageSize,
IPackageDataObserver observer) {
try {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 2a04c39..29f594f 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -23,6 +23,7 @@
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentSender;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -1116,6 +1117,20 @@
}
/**
+ * Call {@link Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int,
+ * Bundle)} from the fragment's containing Activity.
+ */
+ public void startIntentSenderForResult(IntentSender intent, int requestCode,
+ @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
+ Bundle options) throws IntentSender.SendIntentException {
+ if (mHost == null) {
+ throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+ }
+ mHost.onStartIntentSenderFromFragment(this, intent, requestCode, fillInIntent, flagsMask,
+ flagsValues, extraFlags, options);
+ }
+
+ /**
* Receive the result from a previous call to
* {@link #startActivityForResult(Intent, int)}. This follows the
* related Activity API as described there in
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
index 13517e6..cf6b114 100644
--- a/core/java/android/app/FragmentHostCallback.java
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentSender;
import android.os.Bundle;
import android.os.Handler;
import android.util.ArrayMap;
@@ -131,6 +132,21 @@
}
/**
+ * Starts a new {@link IntentSender} from the given fragment.
+ * See {@link Activity#startIntentSender(IntentSender, Intent, int, int, int, Bundle)}.
+ */
+ public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent,
+ int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
+ int extraFlags, Bundle options) throws IntentSender.SendIntentException {
+ if (requestCode != -1) {
+ throw new IllegalStateException(
+ "Starting intent sender with a requestCode requires a FragmentActivity host");
+ }
+ mContext.startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags,
+ options);
+ }
+
+ /**
* Requests permissions from the given fragment.
* See {@link Activity#requestPermissions(String[], int)}
*/
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a759719..400a313 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -25,10 +25,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
@@ -43,6 +46,7 @@
import android.os.Parcelable;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.text.BidiFormatter;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
@@ -588,8 +592,8 @@
private static final int COLOR_INVALID = 1;
/**
- * Sphere of visibility of this notification, which affects how and when the SystemUI reveals
- * the notification's presence and contents in untrusted situations (namely, on the secure
+ * Sphere of visibility of this notification, which affects how and when the SystemUI reveals
+ * the notification's presence and contents in untrusted situations (namely, on the secure
* lockscreen).
*
* The default level, {@link #VISIBILITY_PRIVATE}, behaves exactly as notifications have always
@@ -777,6 +781,16 @@
/**
* {@link #extras} key: this is the remote input history, as supplied to
* {@link Builder#setRemoteInputHistory(CharSequence[])}.
+ *
+ * Apps can fill this through {@link Builder#setRemoteInputHistory(CharSequence[])}
+ * with the most recent inputs that have been sent through a {@link RemoteInput} of this
+ * Notification and are expected to clear it once the it is no longer relevant (e.g. for chat
+ * notifications once the other party has responded).
+ *
+ * The extra with this key is of type CharSequence[] and contains the most recent entry at
+ * the 0 index, the second most recent at the 1 index, etc.
+ *
+ * @see Builder#setRemoteInputHistory(CharSequence[])
*/
public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
@@ -958,6 +972,12 @@
*/
public static final String EXTRA_CONTAINS_CUSTOM_VIEW = "android.contains.customView";
+ /**
+ * @SystemApi
+ * @hide
+ */
+ public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
+
private Icon mSmallIcon;
private Icon mLargeIcon;
@@ -2227,7 +2247,8 @@
Log.d(TAG, "Unknown style class: " + templateClass);
} else {
try {
- final Constructor<? extends Style> ctor = styleClass.getConstructor();
+ final Constructor<? extends Style> ctor =
+ styleClass.getDeclaredConstructor();
ctor.setAccessible(true);
final Style style = ctor.newInstance();
style.restoreFromExtras(mN.extras);
@@ -3126,6 +3147,18 @@
* @param hasProgress whether the progress bar should be shown and set
*/
private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) {
+ final Bundle ex = mN.extras;
+
+ CharSequence title = processLegacyText(ex.getCharSequence(EXTRA_TITLE));
+ CharSequence text = processLegacyText(ex.getCharSequence(EXTRA_TEXT));
+ return applyStandardTemplate(resId, hasProgress, title, text);
+ }
+
+ /**
+ * @param hasProgress whether the progress bar should be shown and set
+ */
+ private RemoteViews applyStandardTemplate(int resId, boolean hasProgress,
+ CharSequence title, CharSequence text) {
RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
resetStandardTemplate(contentView);
@@ -3134,17 +3167,15 @@
bindNotificationHeader(contentView);
bindLargeIcon(contentView);
- if (ex.getCharSequence(EXTRA_TITLE) != null) {
+ if (title != null) {
contentView.setViewVisibility(R.id.title, View.VISIBLE);
- contentView.setTextViewText(R.id.title,
- processLegacyText(ex.getCharSequence(EXTRA_TITLE)));
+ contentView.setTextViewText(R.id.title, title);
}
boolean showProgress = handleProgressBar(hasProgress, contentView, ex);
- if (ex.getCharSequence(EXTRA_TEXT) != null) {
+ if (text != null) {
int textId = showProgress ? com.android.internal.R.id.text_line_1
: com.android.internal.R.id.text;
- contentView.setTextViewText(textId, processLegacyText(
- ex.getCharSequence(EXTRA_TEXT)));
+ contentView.setTextViewText(textId, text);
contentView.setViewVisibility(textId, View.VISIBLE);
}
@@ -3256,14 +3287,38 @@
}
}
- private void bindHeaderAppName(RemoteViews contentView) {
- CharSequence appName = mContext.getPackageManager()
- .getApplicationLabel(mContext.getApplicationInfo());
-
- if (TextUtils.isEmpty(appName)) {
- return;
+ private String loadHeaderAppName() {
+ CharSequence name = null;
+ final PackageManager pm = mContext.getPackageManager();
+ if (mN.extras.containsKey(EXTRA_SUBSTITUTE_APP_NAME)) {
+ // only system packages which lump together a bunch of unrelated stuff
+ // may substitute a different name to make the purpose of the
+ // notification more clear. the correct package label should always
+ // be accessible via SystemUI.
+ final String pkg = mContext.getPackageName();
+ final String subName = mN.extras.getString(EXTRA_SUBSTITUTE_APP_NAME);
+ if (PackageManager.PERMISSION_GRANTED == pm.checkPermission(
+ android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, pkg)) {
+ name = subName;
+ } else {
+ Log.w(TAG, "warning: pkg "
+ + pkg + " attempting to substitute app name '" + subName
+ + "' without holding perm "
+ + android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME);
+ }
}
- contentView.setTextViewText(R.id.app_name_text, appName);
+ if (TextUtils.isEmpty(name)) {
+ name = pm.getApplicationLabel(mContext.getApplicationInfo());
+ }
+ if (TextUtils.isEmpty(name)) {
+ // still nothing?
+ return null;
+ }
+
+ return String.valueOf(name);
+ }
+ private void bindHeaderAppName(RemoteViews contentView) {
+ contentView.setTextViewText(R.id.app_name_text, loadHeaderAppName());
contentView.setTextColor(R.id.app_name_text, resolveContrastColor());
}
@@ -3295,7 +3350,16 @@
}
private RemoteViews applyStandardTemplateWithActions(int layoutId) {
- RemoteViews big = applyStandardTemplate(layoutId);
+ final Bundle ex = mN.extras;
+
+ CharSequence title = processLegacyText(ex.getCharSequence(EXTRA_TITLE));
+ CharSequence text = processLegacyText(ex.getCharSequence(EXTRA_TEXT));
+ return applyStandardTemplateWithActions(layoutId, true /* hasProgress */, title, text);
+ }
+
+ private RemoteViews applyStandardTemplateWithActions(int layoutId, boolean hasProgress,
+ CharSequence title, CharSequence text) {
+ RemoteViews big = applyStandardTemplate(layoutId, hasProgress, title, text);
resetStandardTemplateWithActions(big);
@@ -3749,6 +3813,10 @@
return R.layout.notification_template_material_inbox;
}
+ private int getMessagingLayoutResource() {
+ return R.layout.notification_template_material_messaging;
+ }
+
private int getActionLayoutResource() {
return R.layout.notification_material_action;
}
@@ -4375,13 +4443,100 @@
/**
* @hide
*/
- public RemoteViews makeBigContentView() {
- // TODO handset to write implementation
- RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource());
+ @Override
+ public RemoteViews makeContentView() {
+ Message m = findLatestIncomingMessage();
+ CharSequence title = mConversationTitle != null
+ ? mConversationTitle
+ : (m == null) ? null : m.mSender;
+ CharSequence text = (m == null)
+ ? null
+ : mConversationTitle != null ? makeMessageLine(m) : m.mText;
+ return mBuilder.applyStandardTemplate(mBuilder.getBaseLayoutResource(),
+ false /* hasProgress */,
+ title,
+ text);
+ }
+
+ private Message findLatestIncomingMessage() {
+ for (int i = mMessages.size() - 1; i >= 0; i--) {
+ Message m = mMessages.get(i);
+ // Incoming messages have a non-empty sender.
+ if (!TextUtils.isEmpty(m.mSender)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeBigContentView() {
+ CharSequence title = !TextUtils.isEmpty(super.mBigContentTitle)
+ ? super.mBigContentTitle
+ : mConversationTitle;
+ boolean hasTitle = !TextUtils.isEmpty(title);
+
+ RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
+ mBuilder.getMessagingLayoutResource(),
+ false /* hasProgress */,
+ title,
+ null /* text */);
+
+ int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
+ R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6};
+
+ // Make sure all rows are gone in case we reuse a view.
+ for (int rowId : rowIds) {
+ contentView.setViewVisibility(rowId, View.GONE);
+ }
+
+ int i=0;
+ int titlePadding = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_messaging_spacing);
+ contentView.setViewLayoutMarginBottom(R.id.line1, hasTitle ? titlePadding : 0);
+ contentView.setInt(R.id.notification_messaging, "setNumIndentLines",
+ mBuilder.mN.mLargeIcon == null ? 0 : (hasTitle ? 1 : 2));
+
+ int firstMessage = Math.max(0, mMessages.size() - rowIds.length);
+ while (firstMessage + i < mMessages.size() && i < rowIds.length) {
+ Message m = mMessages.get(firstMessage + i);
+ int rowId = rowIds[i];
+
+ contentView.setViewVisibility(rowId, View.VISIBLE);
+ contentView.setTextViewText(rowId, makeMessageLine(m));
+
+ i++;
+ }
return contentView;
}
+ private CharSequence makeMessageLine(Message m) {
+ BidiFormatter bidi = BidiFormatter.getInstance();
+ SpannableStringBuilder sb = new SpannableStringBuilder();
+ if (TextUtils.isEmpty(m.mSender)) {
+ CharSequence replyName = mUserDisplayName == null ? "" : mUserDisplayName;
+ sb.append(bidi.unicodeWrap(replyName),
+ makeFontColorSpan(mBuilder.resolveContrastColor()),
+ 0 /* flags */);
+ } else {
+ sb.append(bidi.unicodeWrap(m.mSender),
+ makeFontColorSpan(Color.BLACK),
+ 0 /* flags */);
+ }
+ CharSequence text = m.mText == null ? "" : m.mText;
+ sb.append(" ").append(bidi.unicodeWrap(text));
+ return sb;
+ }
+
+ private static TextAppearanceSpan makeFontColorSpan(int color) {
+ return new TextAppearanceSpan(null, 0, 0,
+ ColorStateList.valueOf(color), null);
+ }
+
public static final class Message implements Parcelable {
private final CharSequence mText;
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 4c4f128..aef92cf 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -29,6 +29,7 @@
import android.content.res.ResourcesKey;
import android.hardware.display.DisplayManagerGlobal;
import android.os.IBinder;
+import android.os.Trace;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.LocaleList;
@@ -430,37 +431,44 @@
@Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader) {
- final ResourcesKey key = new ResourcesKey(
- resDir,
- splitResDirs,
- overlayDirs,
- libDirs,
- displayId,
- overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
- compatInfo);
- classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
+ "ResourcesManager#createBaseActivityResources");
+ final ResourcesKey key = new ResourcesKey(
+ resDir,
+ splitResDirs,
+ overlayDirs,
+ libDirs,
+ displayId,
+ overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ compatInfo);
+ classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
- if (DEBUG) {
- Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
- + " with key=" + key);
- }
-
- synchronized (this) {
- final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
- activityToken);
-
- if (overrideConfig != null) {
- activityResources.overrideConfig.setTo(overrideConfig);
- } else {
- activityResources.overrideConfig.setToDefaults();
+ if (DEBUG) {
+ Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+ + " with key=" + key);
}
+
+ synchronized (this) {
+ final ActivityResources activityResources =
+ getOrCreateActivityResourcesStructLocked(
+ activityToken);
+
+ if (overrideConfig != null) {
+ activityResources.overrideConfig.setTo(overrideConfig);
+ } else {
+ activityResources.overrideConfig.setToDefaults();
+ }
+ }
+
+ // Update any existing Activity Resources references.
+ updateResourcesForActivity(activityToken, overrideConfig);
+
+ // Now request an actual Resources object.
+ return getOrCreateResources(activityToken, key, classLoader);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
-
- // Update any existing Activity Resources references.
- updateResourcesForActivity(activityToken, overrideConfig);
-
- // Now request an actual Resources object.
- return getOrCreateResources(activityToken, key, classLoader);
}
/**
@@ -490,8 +498,8 @@
}
if (activityToken != null) {
- final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
- activityToken);
+ final ActivityResources activityResources =
+ getOrCreateActivityResourcesStructLocked(activityToken);
// Clean up any dead references so they don't pile up.
ArrayUtils.unstableRemoveIf(activityResources.activityResources,
@@ -539,6 +547,7 @@
final String[] systemLocales = findSystemLocales
? AssetManager.getSystem().getLocales() : null;
final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
+
// Avoid checking for non-pseudo-locales if we already know there were some from a previous
// Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
// since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
@@ -613,16 +622,21 @@
@Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader) {
- final ResourcesKey key = new ResourcesKey(
- resDir,
- splitResDirs,
- overlayDirs,
- libDirs,
- displayId,
- overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
- compatInfo);
- classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
- return getOrCreateResources(activityToken, key, classLoader);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
+ final ResourcesKey key = new ResourcesKey(
+ resDir,
+ splitResDirs,
+ overlayDirs,
+ libDirs,
+ displayId,
+ overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ compatInfo);
+ classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+ return getOrCreateResources(activityToken, key, classLoader);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ }
}
/**
@@ -636,93 +650,104 @@
*/
public void updateResourcesForActivity(@NonNull IBinder activityToken,
@Nullable Configuration overrideConfig) {
- synchronized (this) {
- final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
- activityToken);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
+ "ResourcesManager#updateResourcesForActivity");
+ synchronized (this) {
+ final ActivityResources activityResources =
+ getOrCreateActivityResourcesStructLocked(activityToken);
- if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
- // They are the same, no work to do.
- return;
- }
-
- // Grab a copy of the old configuration so we can create the delta's of each
- // Resources object associated with this Activity.
- final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
-
- // Update the Activity's base override.
- if (overrideConfig != null) {
- activityResources.overrideConfig.setTo(overrideConfig);
- } else {
- activityResources.overrideConfig.setToDefaults();
- }
-
- if (DEBUG) {
- Throwable here = new Throwable();
- here.fillInStackTrace();
- Slog.d(TAG, "updating resources override for activity=" + activityToken
- + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig)
- + " to newConfig="
- + Configuration.resourceQualifierString(activityResources.overrideConfig),
- here);
- }
-
- final boolean activityHasOverrideConfig =
- !activityResources.overrideConfig.equals(Configuration.EMPTY);
-
- // Rebase each Resources associated with this Activity.
- final int refCount = activityResources.activityResources.size();
- for (int i = 0; i < refCount; i++) {
- WeakReference<Resources> weakResRef = activityResources.activityResources.get(i);
- Resources resources = weakResRef.get();
- if (resources == null) {
- continue;
+ if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
+ // They are the same, no work to do.
+ return;
}
- // Extract the ResourcesKey that was last used to create the Resources for this
- // activity.
- final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
- if (oldKey == null) {
- Slog.e(TAG, "can't find ResourcesKey for resources impl="
- + resources.getImpl());
- continue;
- }
+ // Grab a copy of the old configuration so we can create the delta's of each
+ // Resources object associated with this Activity.
+ final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
- // Build the new override configuration for this ResourcesKey.
- final Configuration rebasedOverrideConfig = new Configuration();
+ // Update the Activity's base override.
if (overrideConfig != null) {
- rebasedOverrideConfig.setTo(overrideConfig);
+ activityResources.overrideConfig.setTo(overrideConfig);
+ } else {
+ activityResources.overrideConfig.setToDefaults();
}
- if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
- // Generate a delta between the old base Activity override configuration and
- // the actual final override configuration that was used to figure out the real
- // delta this Resources object wanted.
- Configuration overrideOverrideConfig = Configuration.generateDelta(
- oldConfig, oldKey.mOverrideConfiguration);
- rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
- }
-
- // Create the new ResourcesKey with the rebased override config.
- final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs,
- oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
- rebasedOverrideConfig, oldKey.mCompatInfo);
-
if (DEBUG) {
- Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
- + " to newKey=" + newKey);
+ Throwable here = new Throwable();
+ here.fillInStackTrace();
+ Slog.d(TAG, "updating resources override for activity=" + activityToken
+ + " from oldConfig="
+ + Configuration.resourceQualifierString(oldConfig)
+ + " to newConfig="
+ + Configuration.resourceQualifierString(
+ activityResources.overrideConfig),
+ here);
}
- ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
- if (resourcesImpl == null) {
- resourcesImpl = createResourcesImpl(newKey);
- mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
- }
+ final boolean activityHasOverrideConfig =
+ !activityResources.overrideConfig.equals(Configuration.EMPTY);
- if (resourcesImpl != resources.getImpl()) {
- // Set the ResourcesImpl, updating it for all users of this Resources object.
- resources.setImpl(resourcesImpl);
+ // Rebase each Resources associated with this Activity.
+ final int refCount = activityResources.activityResources.size();
+ for (int i = 0; i < refCount; i++) {
+ WeakReference<Resources> weakResRef = activityResources.activityResources.get(
+ i);
+ Resources resources = weakResRef.get();
+ if (resources == null) {
+ continue;
+ }
+
+ // Extract the ResourcesKey that was last used to create the Resources for this
+ // activity.
+ final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
+ if (oldKey == null) {
+ Slog.e(TAG, "can't find ResourcesKey for resources impl="
+ + resources.getImpl());
+ continue;
+ }
+
+ // Build the new override configuration for this ResourcesKey.
+ final Configuration rebasedOverrideConfig = new Configuration();
+ if (overrideConfig != null) {
+ rebasedOverrideConfig.setTo(overrideConfig);
+ }
+
+ if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
+ // Generate a delta between the old base Activity override configuration and
+ // the actual final override configuration that was used to figure out the
+ // real delta this Resources object wanted.
+ Configuration overrideOverrideConfig = Configuration.generateDelta(
+ oldConfig, oldKey.mOverrideConfiguration);
+ rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
+ }
+
+ // Create the new ResourcesKey with the rebased override config.
+ final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir,
+ oldKey.mSplitResDirs,
+ oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
+ rebasedOverrideConfig, oldKey.mCompatInfo);
+
+ if (DEBUG) {
+ Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
+ + " to newKey=" + newKey);
+ }
+
+ ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
+ if (resourcesImpl == null) {
+ resourcesImpl = createResourcesImpl(newKey);
+ mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
+ }
+
+ if (resourcesImpl != resources.getImpl()) {
+ // Set the ResourcesImpl, updating it for all users of this Resources
+ // object.
+ resources.setImpl(resourcesImpl);
+ }
}
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
}
@@ -745,86 +770,95 @@
public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
@Nullable CompatibilityInfo compat) {
- if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
- if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
- + mResConfiguration.seq + ", newSeq=" + config.seq);
- return false;
- }
- int changes = mResConfiguration.updateFrom(config);
- // Things might have changed in display manager, so clear the cached displays.
- mDisplays.clear();
- DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
+ "ResourcesManager#applyConfigurationToResourcesLocked");
- if (compat != null && (mResCompatibilityInfo == null ||
- !mResCompatibilityInfo.equals(compat))) {
- mResCompatibilityInfo = compat;
- changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
- | ActivityInfo.CONFIG_SCREEN_SIZE
- | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
- }
+ if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
+ if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
+ + mResConfiguration.seq + ", newSeq=" + config.seq);
+ return false;
+ }
+ int changes = mResConfiguration.updateFrom(config);
+ // Things might have changed in display manager, so clear the cached displays.
+ mDisplays.clear();
+ DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
- Configuration localeAdjustedConfig = config;
- final LocaleList configLocales = config.getLocales();
- if (!configLocales.isEmpty()) {
- setDefaultLocalesLocked(configLocales);
- final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
- if (adjustedLocales != configLocales) { // has the same result as .equals() in this case
- // The first locale in the list was not chosen. So we create a modified
- // configuration with the adjusted locales (which moves the chosen locale to the
- // front).
- localeAdjustedConfig = new Configuration();
- localeAdjustedConfig.setTo(config);
- localeAdjustedConfig.setLocales(adjustedLocales);
- // Also adjust the locale list in mResConfiguration, so that the Resources created
- // later would have the same locale list.
- if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
- mResConfiguration.setLocales(adjustedLocales);
- changes |= ActivityInfo.CONFIG_LOCALE;
+ if (compat != null && (mResCompatibilityInfo == null ||
+ !mResCompatibilityInfo.equals(compat))) {
+ mResCompatibilityInfo = compat;
+ changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
+ | ActivityInfo.CONFIG_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+ }
+
+ Configuration localeAdjustedConfig = config;
+ final LocaleList configLocales = config.getLocales();
+ if (!configLocales.isEmpty()) {
+ setDefaultLocalesLocked(configLocales);
+ final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
+ if (adjustedLocales
+ != configLocales) { // has the same result as .equals() in this case
+ // The first locale in the list was not chosen. So we create a modified
+ // configuration with the adjusted locales (which moves the chosen locale to the
+ // front).
+ localeAdjustedConfig = new Configuration();
+ localeAdjustedConfig.setTo(config);
+ localeAdjustedConfig.setLocales(adjustedLocales);
+ // Also adjust the locale list in mResConfiguration, so that the Resources
+ // created later would have the same locale list.
+ if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
+ mResConfiguration.setLocales(adjustedLocales);
+ changes |= ActivityInfo.CONFIG_LOCALE;
+ }
}
}
- }
- Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat);
+ Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics,
+ compat);
- ApplicationPackageManager.configurationChanged();
- //Slog.i(TAG, "Configuration changed in " + currentPackageName());
+ ApplicationPackageManager.configurationChanged();
+ //Slog.i(TAG, "Configuration changed in " + currentPackageName());
- Configuration tmpConfig = null;
+ Configuration tmpConfig = null;
- for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
- ResourcesKey key = mResourceImpls.keyAt(i);
- ResourcesImpl r = mResourceImpls.valueAt(i).get();
- if (r != null) {
- if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
- + r + " config to: " + localeAdjustedConfig);
- int displayId = key.mDisplayId;
- boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
- DisplayMetrics dm = defaultDisplayMetrics;
- final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
- if (!isDefaultDisplay || hasOverrideConfiguration) {
- if (tmpConfig == null) {
- tmpConfig = new Configuration();
+ for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
+ ResourcesKey key = mResourceImpls.keyAt(i);
+ ResourcesImpl r = mResourceImpls.valueAt(i).get();
+ if (r != null) {
+ if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+ + r + " config to: " + localeAdjustedConfig);
+ int displayId = key.mDisplayId;
+ boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+ DisplayMetrics dm = defaultDisplayMetrics;
+ final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
+ if (!isDefaultDisplay || hasOverrideConfiguration) {
+ if (tmpConfig == null) {
+ tmpConfig = new Configuration();
+ }
+ tmpConfig.setTo(localeAdjustedConfig);
+ if (!isDefaultDisplay) {
+ dm = getDisplayMetrics(displayId);
+ applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
+ }
+ if (hasOverrideConfiguration) {
+ tmpConfig.updateFrom(key.mOverrideConfiguration);
+ }
+ r.updateConfiguration(tmpConfig, dm, compat);
+ } else {
+ r.updateConfiguration(localeAdjustedConfig, dm, compat);
}
- tmpConfig.setTo(localeAdjustedConfig);
- if (!isDefaultDisplay) {
- dm = getDisplayMetrics(displayId);
- applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
- }
- if (hasOverrideConfiguration) {
- tmpConfig.updateFrom(key.mOverrideConfiguration);
- }
- r.updateConfiguration(tmpConfig, dm, compat);
+ //Slog.i(TAG, "Updated app resources " + v.getKey()
+ // + " " + r + ": " + r.getConfiguration());
} else {
- r.updateConfiguration(localeAdjustedConfig, dm, compat);
+ //Slog.i(TAG, "Removing old resources " + v.getKey());
+ mResourceImpls.removeAt(i);
}
- //Slog.i(TAG, "Updated app resources " + v.getKey()
- // + " " + r + ": " + r.getConfiguration());
- } else {
- //Slog.i(TAG, "Removing old resources " + v.getKey());
- mResourceImpls.removeAt(i);
}
- }
- return changes != 0;
+ return changes != 0;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ }
}
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d5d4ca7..cd6e572 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -532,7 +532,8 @@
public WifiScanner createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context.WIFI_SCANNING_SERVICE);
IWifiScanner service = IWifiScanner.Stub.asInterface(b);
- return new WifiScanner(ctx.getOuterContext(), service);
+ return new WifiScanner(ctx.getOuterContext(), service,
+ ConnectivityThread.getInstanceLooper());
}});
registerService(Context.WIFI_RTT_SERVICE, RttManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 96757bb..269089e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -5762,7 +5762,7 @@
* @throws SecurityException if {@code admin} is not an active administrator.
*/
public void setShortSupportMessage(@NonNull ComponentName admin,
- @Nullable String message) {
+ @Nullable CharSequence message) {
if (mService != null) {
try {
mService.setShortSupportMessage(admin, message);
@@ -5776,11 +5776,11 @@
* Called by a device admin to get the short support message.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @return The message set by {@link #setShortSupportMessage(ComponentName, String)} or null if
- * no message has been set.
+ * @return The message set by {@link #setShortSupportMessage(ComponentName, CharSequence)} or
+ * null if no message has been set.
* @throws SecurityException if {@code admin} is not an active administrator.
*/
- public String getShortSupportMessage(@NonNull ComponentName admin) {
+ public CharSequence getShortSupportMessage(@NonNull ComponentName admin) {
if (mService != null) {
try {
return mService.getShortSupportMessage(admin);
@@ -5806,7 +5806,7 @@
* @throws SecurityException if {@code admin} is not an active administrator.
*/
public void setLongSupportMessage(@NonNull ComponentName admin,
- @Nullable String message) {
+ @Nullable CharSequence message) {
if (mService != null) {
try {
mService.setLongSupportMessage(admin, message);
@@ -5820,11 +5820,11 @@
* Called by a device admin to get the long support message.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @return The message set by {@link #setLongSupportMessage(ComponentName, String)} or null if
- * no message has been set.
+ * @return The message set by {@link #setLongSupportMessage(ComponentName, CharSequence)} or
+ * null if no message has been set.
* @throws SecurityException if {@code admin} is not an active administrator.
*/
- public String getLongSupportMessage(@NonNull ComponentName admin) {
+ public CharSequence getLongSupportMessage(@NonNull ComponentName admin) {
if (mService != null) {
try {
return mService.getLongSupportMessage(admin);
@@ -5840,11 +5840,12 @@
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param userHandle user id the admin is running as.
- * @return The message set by {@link #setShortSupportMessage(ComponentName, String)}
+ * @return The message set by {@link #setShortSupportMessage(ComponentName, CharSequence)}
*
* @hide
*/
- public String getShortSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+ public CharSequence getShortSupportMessageForUser(@NonNull ComponentName admin,
+ int userHandle) {
if (mService != null) {
try {
return mService.getShortSupportMessageForUser(admin, userHandle);
@@ -5861,11 +5862,11 @@
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param userHandle user id the admin is running as.
- * @return The message set by {@link #setLongSupportMessage(ComponentName, String)}
+ * @return The message set by {@link #setLongSupportMessage(ComponentName, CharSequence)}
*
* @hide
*/
- public String getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+ public CharSequence getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
if (mService != null) {
try {
return mService.getLongSupportMessageForUser(admin, userHandle);
@@ -6050,11 +6051,13 @@
* {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent}.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @param color The 32bit representation of the color to be used.
+ * @param color The 24bit (0xRRGGBB) representation of the color to be used.
* @throws SecurityException if {@code admin} is not a profile owner.
*/
public void setOrganizationColor(@NonNull ComponentName admin, int color) {
try {
+ // always enforce alpha channel to have 100% opacity
+ color |= 0xFF000000;
mService.setOrganizationColor(admin, color);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -6066,7 +6069,7 @@
*
* Sets the color used for customization.
*
- * @param color The 32bit representation of the color to be used.
+ * @param color The 24bit (0xRRGGBB) representation of the color to be used.
* @param userId which user to set the color to.
* @RequiresPermission(allOf = {
* Manifest.permission.MANAGE_USERS,
@@ -6074,6 +6077,8 @@
*/
public void setOrganizationColorForUser(@ColorInt int color, @UserIdInt int userId) {
try {
+ // always enforce alpha channel to have 100% opacity
+ color |= 0xFF000000;
mService.setOrganizationColorForUser(color, userId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -6085,10 +6090,10 @@
* This color is used as background color of the confirm credentials screen for that user.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @return The 32bit representation of the color to be used.
+ * @return The 24bit (0xRRGGBB) representation of the color to be used.
* @throws SecurityException if {@code admin} is not a profile owner.
*/
- public int getOrganizationColor(@NonNull ComponentName admin) {
+ public @ColorInt int getOrganizationColor(@NonNull ComponentName admin) {
try {
return mService.getOrganizationColor(admin);
} catch (RemoteException re) {
@@ -6101,9 +6106,9 @@
* Retrieve the customization color for a given user.
*
* @param userHandle The user id of the user we're interested in.
- * @return The 32bit representation of the color to be used.
+ * @return The 24bit (0xRRGGBB) representation of the color to be used.
*/
- public int getOrganizationColorForUser(int userHandle) {
+ public @ColorInt int getOrganizationColorForUser(int userHandle) {
try {
return mService.getOrganizationColorForUser(userHandle);
} catch (RemoteException re) {
@@ -6123,7 +6128,7 @@
* @param title The organization name or {@code null} to clear a previously set name.
* @throws SecurityException if {@code admin} is not a profile owner.
*/
- public void setOrganizationName(@NonNull ComponentName admin, @Nullable String title) {
+ public void setOrganizationName(@NonNull ComponentName admin, @Nullable CharSequence title) {
try {
mService.setOrganizationName(admin, title);
} catch (RemoteException re) {
@@ -6139,7 +6144,7 @@
* @return The organization name or {@code null} if none is set.
* @throws SecurityException if {@code admin} is not a profile owner.
*/
- public String getOrganizationName(@NonNull ComponentName admin) {
+ public CharSequence getOrganizationName(@NonNull ComponentName admin) {
try {
return mService.getOrganizationName(admin);
} catch (RemoteException re) {
@@ -6155,7 +6160,7 @@
*
* @hide
*/
- public String getOrganizationNameForUser(int userHandle) {
+ public CharSequence getOrganizationNameForUser(int userHandle) {
try {
return mService.getOrganizationNameForUser(userHandle);
} catch (RemoteException re) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 6df1038..cba64c2 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -269,13 +269,13 @@
String getWifiMacAddress(in ComponentName admin);
void reboot(in ComponentName admin);
- void setShortSupportMessage(in ComponentName admin, in String message);
- String getShortSupportMessage(in ComponentName admin);
- void setLongSupportMessage(in ComponentName admin, in String message);
- String getLongSupportMessage(in ComponentName admin);
+ void setShortSupportMessage(in ComponentName admin, in CharSequence message);
+ CharSequence getShortSupportMessage(in ComponentName admin);
+ void setLongSupportMessage(in ComponentName admin, in CharSequence message);
+ CharSequence getLongSupportMessage(in ComponentName admin);
- String getShortSupportMessageForUser(in ComponentName admin, int userHandle);
- String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
+ CharSequence getShortSupportMessageForUser(in ComponentName admin, int userHandle);
+ CharSequence getLongSupportMessageForUser(in ComponentName admin, int userHandle);
boolean isSeparateProfileChallengeAllowed(int userHandle);
@@ -284,9 +284,9 @@
int getOrganizationColor(in ComponentName admin);
int getOrganizationColorForUser(int userHandle);
- void setOrganizationName(in ComponentName admin, in String title);
- String getOrganizationName(in ComponentName admin);
- String getOrganizationNameForUser(int userHandle);
+ void setOrganizationName(in ComponentName admin, in CharSequence title);
+ CharSequence getOrganizationName(in ComponentName admin);
+ CharSequence getOrganizationNameForUser(int userHandle);
int getUserProvisioningState();
void setUserProvisioningState(int state, int userHandle);
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 828ac38..c84a0dc 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -138,12 +138,28 @@
*/
public static final int PRIORITY_TOP_APP = 40;
+ /**
+ * Adjustment of {@link #getPriority} if the app has often (50% or more of the time)
+ * been running jobs.
+ * @hide
+ */
+ public static final int PRIORITY_ADJ_OFTEN_RUNNING = -40;
+
+ /**
+ * Adjustment of {@link #getPriority} if the app has always (90% or more of the time)
+ * been running jobs.
+ * @hide
+ */
+ public static final int PRIORITY_ADJ_ALWAYS_RUNNING = -80;
+
private final int jobId;
private final PersistableBundle extras;
private final ComponentName service;
private final boolean requireCharging;
private final boolean requireDeviceIdle;
private final TriggerContentUri[] triggerContentUris;
+ private final long triggerContentUpdateDelay;
+ private final long triggerContentMaxDelay;
private final boolean hasEarlyConstraint;
private final boolean hasLateConstraint;
private final int networkType;
@@ -207,6 +223,22 @@
}
/**
+ * When triggering on content URI changes, this is the delay from when a change
+ * is detected until the job is scheduled.
+ */
+ public long getTriggerContentUpdateDelay() {
+ return triggerContentUpdateDelay;
+ }
+
+ /**
+ * When triggering on content URI changes, this is the maximum delay we will
+ * use before scheduling the job.
+ */
+ public long getTriggerContentMaxDelay() {
+ return triggerContentMaxDelay;
+ }
+
+ /**
* One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY},
* {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, or
* {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}.
@@ -254,7 +286,8 @@
}
/**
- * Flex time for this job. Only valid if this is a periodic job.
+ * Flex time for this job. Only valid if this is a periodic job. The job can
+ * execute at any time in a window of flex length at the end of the period.
*/
public long getFlexMillis() {
long interval = getIntervalMillis();
@@ -306,6 +339,8 @@
requireCharging = in.readInt() == 1;
requireDeviceIdle = in.readInt() == 1;
triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
+ triggerContentUpdateDelay = in.readLong();
+ triggerContentMaxDelay = in.readLong();
networkType = in.readInt();
minLatencyMillis = in.readLong();
maxExecutionDelayMillis = in.readLong();
@@ -329,6 +364,8 @@
triggerContentUris = b.mTriggerContentUris != null
? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
: null;
+ triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
+ triggerContentMaxDelay = b.mTriggerContentMaxDelay;
networkType = b.mNetworkType;
minLatencyMillis = b.mMinLatencyMillis;
maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
@@ -356,6 +393,8 @@
out.writeInt(requireCharging ? 1 : 0);
out.writeInt(requireDeviceIdle ? 1 : 0);
out.writeTypedArray(triggerContentUris, flags);
+ out.writeLong(triggerContentUpdateDelay);
+ out.writeLong(triggerContentMaxDelay);
out.writeInt(networkType);
out.writeLong(minLatencyMillis);
out.writeLong(maxExecutionDelayMillis);
@@ -467,6 +506,8 @@
private boolean mRequiresDeviceIdle;
private int mNetworkType;
private ArrayList<TriggerContentUri> mTriggerContentUris;
+ private long mTriggerContentUpdateDelay = -1;
+ private long mTriggerContentMaxDelay = -1;
private boolean mIsPersisted;
// One-off parameters.
private long mMinLatencyMillis;
@@ -573,6 +614,27 @@
}
/**
+ * Set the delay (in milliseconds) from when a content change is detected until
+ * the job is scheduled. If there are more changes during that time, the delay
+ * will be reset to start at the time of the most recent change.
+ * @param durationMs Delay after most recent content change, in milliseconds.
+ */
+ public Builder setTriggerContentUpdateDelay(long durationMs) {
+ mTriggerContentUpdateDelay = durationMs;
+ return this;
+ }
+
+ /**
+ * Set the maximum total delay (in milliseconds) that is allowed from the first
+ * time a content change is detected until the job is scheduled.
+ * @param durationMs Delay after initial content change, in milliseconds.
+ */
+ public Builder setTriggerContentMaxDelay(long durationMs) {
+ mTriggerContentMaxDelay = durationMs;
+ return this;
+ }
+
+ /**
* Specify that this job should recur with the provided interval, not more than once per
* period. You have no control over when within this interval this job will be executed,
* only the guarantee that it will be executed at most once within this interval.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7e67e8d..831de4a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -765,6 +765,19 @@
= "android.intent.action.APPLICATION_PREFERENCES";
/**
+ * Activity Action: Launch an activity showing the app information.
+ * For applications which install other applications (such as app stores), it is recommended
+ * to handle this action for providing the app information to the user.
+ *
+ * <p>Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose information needs
+ * to be displayed.
+ * <p>Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SHOW_APP_INFO
+ = "android.intent.action.SHOW_APP_INFO";
+
+ /**
* Represents a shortcut/live folder icon resource.
*
* @see Intent#ACTION_CREATE_SHORTCUT
@@ -1683,9 +1696,7 @@
* Type: String
* </p>
*
- * @hide
*/
- @SystemApi
public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
/**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 104feb5..585d2a3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -366,6 +366,9 @@
*
* <p>NOTE: {@code WebView} does not honor this flag.
*
+ * <p>This flag is ignored on Android N and above if an Android Network Security Config is
+ * present.
+ *
* <p>This flag comes from
* {@link android.R.styleable#AndroidManifestApplication_usesCleartextTraffic
* android:usesCleartextTraffic} of the <application> tag.
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 46321a4..430c7e7 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IOnAppsChangedListener;
import android.content.pm.ParceledListSlice;
@@ -37,7 +38,7 @@
void addOnAppsChangedListener(String callingPackage, in IOnAppsChangedListener listener);
void removeOnAppsChangedListener(in IOnAppsChangedListener listener);
ParceledListSlice getLauncherActivities(String packageName, in UserHandle user);
- ResolveInfo resolveActivity(in Intent intent, in UserHandle user);
+ ActivityInfo resolveActivity(in ComponentName component, in UserHandle user);
void startActivityAsUser(in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
void showAppDetailsAsUser(in ComponentName component, in Rect sourceBounds,
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 6fce36b..0526815 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -388,6 +388,15 @@
void deleteApplicationCacheFiles(in String packageName, IPackageDataObserver observer);
/**
+ * Delete all the cache files in an applications cache directory
+ * @param packageName The package name of the application whose cache
+ * files need to be deleted
+ * @param userId the user to delete application cache for
+ * @param observer a callback used to notify when the deletion is finished.
+ */
+ void deleteApplicationCacheFilesAsUser(in String packageName, int userId, IPackageDataObserver observer);
+
+ /**
* Clear the user data directory of an application.
* @param packageName The package name of the application whose cache
* files need to be deleted
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 31d377b..9c90346 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -28,11 +28,12 @@
ParceledListSlice getDynamicShortcuts(String packageName, int userId);
- boolean addDynamicShortcut(String packageName, in ShortcutInfo shortcutInfo, int userId);
+ boolean addDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList,
+ int userId);
- void deleteDynamicShortcut(String packageName, in String shortcutId, int userId);
+ void removeDynamicShortcuts(String packageName, in List shortcutIds, int userId);
- void deleteAllDynamicShortcuts(String packageName, int userId);
+ void removeAllDynamicShortcuts(String packageName, int userId);
ParceledListSlice getPinnedShortcuts(String packageName, int userId);
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 40e1a9f..2beca7b 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -39,7 +39,6 @@
private ActivityInfo mActivityInfo;
private ComponentName mComponentName;
- private ResolveInfo mResolveInfo;
private UserHandle mUser;
/**
@@ -49,11 +48,10 @@
* @param info ResolveInfo from which to create the LauncherActivityInfo.
* @param user The UserHandle of the profile to which this activity belongs.
*/
- LauncherActivityInfo(Context context, ResolveInfo info, UserHandle user) {
+ LauncherActivityInfo(Context context, ActivityInfo info, UserHandle user) {
this(context);
- mResolveInfo = info;
- mActivityInfo = info.activityInfo;
- mComponentName = LauncherApps.getComponentName(info);
+ mActivityInfo = info;
+ mComponentName = new ComponentName(info.packageName, info.name);
mUser = user;
}
@@ -91,7 +89,7 @@
* @return The label for the activity.
*/
public CharSequence getLabel() {
- return mResolveInfo.loadLabel(mPm);
+ return mActivityInfo.loadLabel(mPm);
}
/**
@@ -103,7 +101,7 @@
* @return The drawable associated with the activity.
*/
public Drawable getIcon(int density) {
- final int iconRes = mResolveInfo.getIconResourceInternal();
+ final int iconRes = mActivityInfo.getIconResource();
Drawable icon = null;
// Get the preferred density icon from the app's resources
if (density != 0 && iconRes != 0) {
@@ -116,7 +114,7 @@
}
// Get the default density icon
if (icon == null) {
- icon = mResolveInfo.loadIcon(mPm);
+ icon = mActivityInfo.loadIcon(mPm);
}
return icon;
}
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index a0d2339..824722d 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -39,6 +39,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -291,7 +292,7 @@
}
ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>();
for (ResolveInfo ri : activities.getList()) {
- LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri, user);
+ LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
if (DEBUG) {
Log.v(TAG, "Returning activity for profile " + user + " : "
+ lai.getComponentName());
@@ -301,10 +302,6 @@
return lais;
}
- static ComponentName getComponentName(ResolveInfo ri) {
- return new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
- }
-
/**
* Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
* returns null.
@@ -315,9 +312,9 @@
*/
public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
try {
- ResolveInfo ri = mService.resolveActivity(intent, user);
- if (ri != null) {
- LauncherActivityInfo info = new LauncherActivityInfo(mContext, ri, user);
+ ActivityInfo ai = mService.resolveActivity(intent.getComponent(), user);
+ if (ai != null) {
+ LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
return info;
}
} catch (RemoteException re) {
@@ -389,6 +386,7 @@
*
* @return An {@link ApplicationInfo} containing information about the package or
* null of the package isn't found.
+ * @hide
*/
public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags,
UserHandle user) {
@@ -493,43 +491,24 @@
}
/**
- * Return the icon resource ID, if {@code shortcut} has one
- * (i.e. when {@link ShortcutInfo#hasIconResource()} returns {@code true}).
- *
- * <p>Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
- *
- * @param shortcut The target shortcut.
+ * @hide kept for testing.
*/
public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
- return getShortcutIconResId(shortcut.getPackageName(), shortcut.getId(),
- shortcut.getUserId());
+ return shortcut.getIconResourceId();
}
/**
- * Return the icon resource ID, if {@code shortcut} has one
- * (i.e. when {@link ShortcutInfo#hasIconResource()} returns {@code true}).
- *
- * <p>Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
- *
- * @param packageName The target package name.
- * @param shortcutId The ID of the shortcut to lad rom.
- * @param user The UserHandle of the profile.
+ * @hide kept for testing.
*/
public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
@NonNull UserHandle user) {
- return getShortcutIconResId(packageName, shortcutId, user.getIdentifier());
- }
+ final ShortcutQuery q = new ShortcutQuery();
+ q.setPackage(packageName);
+ q.setShortcutIds(Arrays.asList(shortcutId));
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
- private int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
- int userId) {
- try {
- return mService.getShortcutIconResId(mContext.getPackageName(),
- packageName, shortcutId, userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
}
/**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 39bc783..ade2248 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4972,6 +4972,27 @@
IPackageDataObserver observer);
/**
+ * Attempts to delete the cache files associated with an application for a given user. Since
+ * this may take a little while, the result will be posted back to the given observer. A
+ * deletion will fail if the calling context lacks the
+ * {@link android.Manifest.permission#DELETE_CACHE_FILES} permission, if the named package
+ * cannot be found, or if the named package is a "system package". If {@code userId} does not
+ * belong to the calling user, the caller must have
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
+ *
+ * @param packageName The name of the package to delete
+ * @param userId the user for which the cache files needs to be deleted
+ * @param observer An observer callback to get notified when the cache file deletion is
+ * complete.
+ * {@link android.content.pm.IPackageDataObserver#onRemoveCompleted(String, boolean)}
+ * will be called when that happens. observer may be null to indicate that no
+ * callback is desired.
+ * @hide
+ */
+ public abstract void deleteApplicationCacheFilesAsUser(String packageName, int userId,
+ IPackageDataObserver observer);
+
+ /**
* Free storage by deleting LRU sorted list of cache files across
* all applications. If the currently available free storage
* on the device is greater than or equal to the requested
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 8236f55..995d2cc 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -87,6 +87,11 @@
/**
* Test if the given component is considered installed, enabled and a match
* for the given flags.
+ *
+ * <p>
+ * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and
+ * {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
+ * </p>
*/
public boolean isMatch(ComponentInfo componentInfo, int flags) {
if (!isInstalled(flags)) return false;
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 7a807c4..a900015 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -34,6 +34,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
// TODO Enhance javadoc
/**
@@ -107,6 +109,11 @@
@Retention(RetentionPolicy.SOURCE)
public @interface CloneFlags {}
+ /**
+ * Shortcut category for
+ */
+ public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
+
private final String mId;
@NonNull
@@ -124,6 +131,9 @@
@Nullable
private String mText;
+ @NonNull
+ private List<String> mCategories;
+
/**
* Intent *with extras removed*.
*/
@@ -168,6 +178,7 @@
mIcon = b.mIcon;
mTitle = b.mTitle;
mText = b.mText;
+ mCategories = clone(b.mCategories);
mIntent = b.mIntent;
if (mIntent != null) {
final Bundle intentExtras = mIntent.getExtras();
@@ -181,6 +192,10 @@
updateTimestamp();
}
+ private <T> ArrayList<T> clone(List<T> source) {
+ return (source == null) ? null : new ArrayList<>(source);
+ }
+
/**
* Throws if any of the mandatory fields is not set.
*
@@ -202,17 +217,20 @@
mFlags = source.mFlags;
mLastChangedTimestamp = source.mLastChangedTimestamp;
+ // Just always keep it since it's cheep.
+ mIconResourceId = source.mIconResourceId;
+
if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
mActivityComponent = source.mActivityComponent;
if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
mIcon = source.mIcon;
mBitmapPath = source.mBitmapPath;
- mIconResourceId = source.mIconResourceId;
}
mTitle = source.mTitle;
mText = source.mText;
+ mCategories = clone(source.mCategories);
if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
@@ -262,6 +280,9 @@
if (source.mText != null) {
mText = source.mText;
}
+ if (source.mCategories != null) {
+ mCategories = clone(source.mCategories);
+ }
if (source.mIntent != null) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
@@ -325,6 +346,8 @@
private String mText;
+ private List<String> mCategories;
+
private Intent mIntent;
private int mWeight;
@@ -369,8 +392,9 @@
*
* <p>For performance reasons, icons will <b>NOT</b> be available on instances
* returned by {@link ShortcutManager} or {@link LauncherApps}. Launcher applications
- * need to use {@link LauncherApps#getShortcutIconFd(ShortcutInfo)}
- * and {@link LauncherApps#getShortcutIconResId(ShortcutInfo)}.
+ * can use {@link ShortcutInfo#getIconResourceId()} if {@link #hasIconResource()} is true.
+ * Otherwise, if {@link #hasIconFile()} is true, use
+ * {@link LauncherApps#getShortcutIconFd} to load the image.
*/
@NonNull
public Builder setIcon(Icon icon) {
@@ -403,6 +427,18 @@
}
/**
+ * Sets categories for a shortcut. Launcher applications may use this information to
+ * categorise shortcuts.
+ *
+ * @see #SHORTCUT_CATEGORY_CONVERSATION
+ */
+ @NonNull
+ public Builder setCategories(List<String> categories) {
+ mCategories = categories;
+ return this;
+ }
+
+ /**
* Sets the intent of a shortcut. This is a mandatory field. The extras must only contain
* persistable information. (See {@link PersistableBundle}).
*/
@@ -500,6 +536,14 @@
}
/**
+ * Return the categories.
+ */
+ @Nullable
+ public List<String> getCategories() {
+ return mCategories;
+ }
+
+ /**
* Return the intent.
*
* <p>All shortcuts must have an intent, but this method will return null when
@@ -662,7 +706,9 @@
mIconResourceId = iconResourceId;
}
- /** @hide */
+ /**
+ * Get the resource ID for the icon, valid only when {@link #hasIconResource()} } is true.
+ */
public int getIconResourceId() {
return mIconResourceId;
}
@@ -687,6 +733,8 @@
mIcon = source.readParcelable(cl);
mTitle = source.readString();
mText = source.readString();
+ mCategories = new ArrayList<>();
+ source.readStringList(mCategories);
mIntent = source.readParcelable(cl);
mIntentPersistableExtras = source.readParcelable(cl);
mWeight = source.readInt();
@@ -706,6 +754,7 @@
dest.writeParcelable(mIcon, flags);
dest.writeString(mTitle);
dest.writeString(mText);
+ dest.writeStringList(mCategories);
dest.writeParcelable(mIntent, flags);
dest.writeParcelable(mIntentPersistableExtras, flags);
dest.writeInt(mWeight);
@@ -770,6 +819,9 @@
sb.append(", text=");
sb.append(secure ? "***" : mText);
+ sb.append(", categories=");
+ sb.append(mCategories);
+
sb.append(", icon=");
sb.append(mIcon);
@@ -807,7 +859,7 @@
/** @hide */
public ShortcutInfo(
@UserIdInt int userId, String id, String packageName, ComponentName activityComponent,
- Icon icon, String title, String text, Intent intent,
+ Icon icon, String title, String text, List<String> categories, Intent intent,
PersistableBundle intentPersistableExtras,
int weight, PersistableBundle extras, long lastChangedTimestamp,
int flags, int iconResId, String bitmapPath) {
@@ -818,6 +870,7 @@
mIcon = icon;
mTitle = title;
mText = text;
+ mCategories = clone(categories);
mIntent = intent;
mIntentPersistableExtras = intentPersistableExtras;
mWeight = weight;
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 919ccda..75803d3 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -34,11 +34,11 @@
* <h3>Dynamic shortcuts and pinned shortcuts</h3>
*
* An application can publish shortcuts with {@link #setDynamicShortcuts(List)} and
- * {@link #addDynamicShortcut(ShortcutInfo)}. There can be at most
+ * {@link #addDynamicShortcuts(List)}. There can be at most
* {@link #getMaxDynamicShortcutCount()} number of dynamic shortcuts at a time from the same
* application.
- * A dynamic shortcut can be deleted with {@link #deleteDynamicShortcut(String)}, and apps
- * can also use {@link #deleteAllDynamicShortcuts()} to delete all dynamic shortcuts.
+ * A dynamic shortcut can be deleted with {@link #removeDynamicShortcuts(List)}, and apps
+ * can also use {@link #removeAllDynamicShortcuts()} to delete all dynamic shortcuts.
*
* <p>The shortcuts that are currently published by the above APIs are called "dynamic", because
* they can be removed by the creator application at any time. The user may "pin" dynamic shortcuts
@@ -61,11 +61,11 @@
*
* <h3>Rate limiting</h3>
*
- * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcut(ShortcutInfo)},
+ * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)},
* and {@link #updateShortcuts(List)} will be
* rate-limited. An application can call these methods at most
* {@link #getRemainingCallCount()} times until the rate-limiting counter is reset,
- * which happens at a certain time every day.
+ * which happens every hour.
*
* <p>An application can use {@link #getRateLimitResetTime()} to get the next reset time.
*
@@ -153,10 +153,10 @@
* @throws IllegalArgumentException if the caller application has already published the
* max number of dynamic shortcuts.
*/
- public boolean addDynamicShortcut(@NonNull ShortcutInfo shortcutInfo) {
+ public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
try {
- return mService.addDynamicShortcut(
- mContext.getPackageName(), shortcutInfo, injectMyUserId());
+ return mService.addDynamicShortcuts(mContext.getPackageName(),
+ new ParceledListSlice(shortcutInfoList), injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -165,9 +165,10 @@
/**
* Delete a single dynamic shortcut by ID.
*/
- public void deleteDynamicShortcut(@NonNull String shortcutId) {
+ public void removeDynamicShortcuts(@NonNull List<String> shortcutIds) {
try {
- mService.deleteDynamicShortcut(mContext.getPackageName(), shortcutId, injectMyUserId());
+ mService.removeDynamicShortcuts(mContext.getPackageName(), shortcutIds,
+ injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -176,9 +177,9 @@
/**
* Delete all dynamic shortcuts from the caller application.
*/
- public void deleteAllDynamicShortcuts() {
+ public void removeAllDynamicShortcuts() {
try {
- mService.deleteAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId());
+ mService.removeAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 79eff4f..98a8904 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1590,16 +1590,16 @@
new Key<Integer>("android.control.videoStabilizationMode", int.class);
/**
- * <p>The amount of additional sesnsitivity boost applied to output images
+ * <p>The amount of additional sensitivity boost applied to output images
* after RAW sensor data is captured.</p>
* <p>Some camera devices support additional digital sensitivity boosting in the
* camera processing pipeline after sensor RAW image is captured.
* Such a boost will be applied to YUV/JPEG format output images but will not
* have effect on RAW output formats like RAW_SENSOR, RAW10, RAW12 or RAW_OPAQUE.</p>
- * <p>This key is optional. Applications can assume there is no boost applied
- * after RAW is captured if this key is not available.
- * When this key is available, the sensitivity boost value must be within
- * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}.</p>
+ * <p>This key will be <code>null</code> for devices that do not support any RAW format
+ * outputs. For devices that do support RAW format outputs, this key will always
+ * present, and if a device does not support post RAW sensitivity boost, it will
+ * list <code>100</code> in this key.</p>
* <p>If the camera device cannot apply the exact boost requested, it will reduce the
* boost to the nearest supported value.
* The final boost value used will be available in the output capture result.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 4f41e1c..8c73e6a 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2097,16 +2097,16 @@
new Key<Integer>("android.control.videoStabilizationMode", int.class);
/**
- * <p>The amount of additional sesnsitivity boost applied to output images
+ * <p>The amount of additional sensitivity boost applied to output images
* after RAW sensor data is captured.</p>
* <p>Some camera devices support additional digital sensitivity boosting in the
* camera processing pipeline after sensor RAW image is captured.
* Such a boost will be applied to YUV/JPEG format output images but will not
* have effect on RAW output formats like RAW_SENSOR, RAW10, RAW12 or RAW_OPAQUE.</p>
- * <p>This key is optional. Applications can assume there is no boost applied
- * after RAW is captured if this key is not available.
- * When this key is available, the sensitivity boost value must be within
- * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}.</p>
+ * <p>This key will be <code>null</code> for devices that do not support any RAW format
+ * outputs. For devices that do support RAW format outputs, this key will always
+ * present, and if a device does not support post RAW sensitivity boost, it will
+ * list <code>100</code> in this key.</p>
* <p>If the camera device cannot apply the exact boost requested, it will reduce the
* boost to the nearest supported value.
* The final boost value used will be available in the output capture result.</p>
@@ -3599,10 +3599,20 @@
/**
* <p>The shading map is a low-resolution floating-point map
- * that lists the coefficients used to correct for vignetting, for each
- * Bayer color channel of RAW image data.</p>
- * <p>The least shaded section of the image should have a gain factor
- * of 1; all other sections should have gains above 1.</p>
+ * that lists the coefficients used to correct for vignetting and color shading,
+ * for each Bayer color channel of RAW image data.</p>
+ * <p>The lens shading correction is defined as a full shading correction that
+ * corrects both color shading for the output non-RAW images. After the
+ * shading map is applied, the output non-RAW images will be flat-field images
+ * for flat scenes under uniform illumination.</p>
+ * <p>When there is no lens shading correction applied to RAW output images
+ * ({@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} <code>==</code> false), this map is a full lens
+ * shading correction map; when there is some lens shading correction applied
+ * to the RAW output image ({@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} <code>==</code> true),
+ * this map reports the remaining lens shading correction map that needs to be
+ * applied to get fully shading corrected images.</p>
+ * <p>For a full shading correction map, the least shaded section of the image
+ * should have a gain factor of 1; all other sections should have gains above 1.</p>
* <p>When {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} = TRANSFORM_MATRIX, the map
* must take into account the colorCorrection settings.</p>
* <p>The shading map is for the entire active pixel array, and is not
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 18a155d..b542339 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -501,11 +501,8 @@
Log.d(TAG, "createCaptureSessionByOutputConfiguration");
}
- // OutputConfiguration objects aren't immutable, make a copy before using.
- List<OutputConfiguration> currentOutputs = new ArrayList<OutputConfiguration>();
- for (OutputConfiguration output : outputConfigurations) {
- currentOutputs.add(new OutputConfiguration(output));
- }
+ // OutputConfiguration objects are immutable, but need to have our own array
+ List<OutputConfiguration> currentOutputs = new ArrayList<>(outputConfigurations);
createCaptureSessionInternal(null, currentOutputs, callback, handler,
/*isConstrainedHighSpeed*/false);
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index cd0c474..61b534b 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -17,6 +17,8 @@
package android.hardware.camera2.params;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.utils.HashCodeHelpers;
@@ -71,12 +73,12 @@
public static final int ROTATION_270 = 3;
/**
- * Invalid surface set ID.
+ * Invalid surface group ID.
*
*<p>An {@link OutputConfiguration} with this value indicates that the included surface
- *doesn't belong to any surface set.</p>
+ *doesn't belong to any surface group.</p>
*/
- public static final int SURFACE_SET_ID_INVALID = -1;
+ public static final int SURFACE_GROUP_ID_NONE = -1;
/**
* Create a new {@link OutputConfiguration} instance with a {@link Surface}.
@@ -84,11 +86,47 @@
* @param surface
* A Surface for camera to output to.
*
- * <p>This constructor creates a default configuration.</p>
+ * <p>This constructor creates a default configuration, with a surface group ID of
+ * {@value #SURFACE_GROUP_ID_NONE}.</p>
*
*/
- public OutputConfiguration(Surface surface) {
- this(surface, ROTATION_0);
+ public OutputConfiguration(@NonNull Surface surface) {
+ this(SURFACE_GROUP_ID_NONE, surface, ROTATION_0);
+ }
+
+ /**
+ * Create a new {@link OutputConfiguration} instance with a {@link Surface},
+ * with a surface group ID.
+ *
+ * <p>
+ * A surface group ID is used to identify which surface group this output surface belongs to. A
+ * surface group is a group of output surfaces that are not intended to receive camera output
+ * buffer streams simultaneously. The {@link CameraDevice} may be able to share the buffers used
+ * by all the surfaces from the same surface group, therefore may reduce the overall memory
+ * footprint. The application should only set the same set ID for the streams that are not
+ * simultaneously streaming. A negative ID indicates that this surface doesn't belong to any
+ * surface group. The default value is {@value #SURFACE_GROUP_ID_NONE}.</p>
+ *
+ * <p>For example, a video chat application that has an adaptive output resolution feature would
+ * need two (or more) output resolutions, to switch resolutions without any output glitches.
+ * However, at any given time, only one output is active to minimize outgoing network bandwidth
+ * and encoding overhead. To save memory, the application should set the video outputs to have
+ * the same non-negative group ID, so that the camera device can share the same memory region
+ * for the alternating outputs.</p>
+ *
+ * <p>It is not an error to include output streams with the same group ID in the same capture
+ * request, but the resulting memory consumption may be higher than if the two streams were
+ * not in the same surface group to begin with, especially if the outputs have substantially
+ * different dimensions.</p>
+ *
+ * @param surfaceGroupId
+ * A group ID for this output, used for sharing memory between multiple outputs.
+ * @param surface
+ * A Surface for camera to output to.
+ *
+ */
+ public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface) {
+ this(surfaceGroupId, surface, ROTATION_0);
}
/**
@@ -100,9 +138,9 @@
* A Surface for camera to output to.
* @param rotation
* The desired rotation to be applied on camera output. Value must be one of
- * ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degree,
+ * ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees,
* application should make sure corresponding surface size has width and height
- * transposed corresponding to the width and height without rotation. For example,
+ * transposed relative to the width and height without rotation. For example,
* if application needs camera to capture 1280x720 picture and rotate it by 90 degree,
* application should set rotation to {@code ROTATION_90} and make sure the
* corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
@@ -110,15 +148,43 @@
* @hide
*/
@SystemApi
- public OutputConfiguration(Surface surface, int rotation) {
+ public OutputConfiguration(@NonNull Surface surface, int rotation) {
+ this(SURFACE_GROUP_ID_NONE, surface, rotation);
+ }
+
+
+ /**
+ * Create a new {@link OutputConfiguration} instance, with rotation and a group ID.
+ *
+ * <p>This constructor takes an argument for desired camera rotation and for the surface group
+ * ID. See {@link #OutputConfiguration(int, Surface)} for details of the group ID.</p>
+ *
+ * @param surfaceGroupId
+ * A group ID for this output, used for sharing memory between multiple outputs.
+ * @param surface
+ * A Surface for camera to output to.
+ * @param rotation
+ * The desired rotation to be applied on camera output. Value must be one of
+ * ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees,
+ * application should make sure corresponding surface size has width and height
+ * transposed relative to the width and height without rotation. For example,
+ * if application needs camera to capture 1280x720 picture and rotate it by 90 degree,
+ * application should set rotation to {@code ROTATION_90} and make sure the
+ * corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
+ * throw {@code IllegalArgumentException} if device cannot perform such rotation.
+ * @hide
+ */
+ @SystemApi
+ public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation) {
checkNotNull(surface, "Surface must not be null");
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
- mSurfaceSetId = SURFACE_SET_ID_INVALID;
+ mSurfaceGroupId = surfaceGroupId;
mSurface = surface;
mRotation = rotation;
mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);
mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface);
mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface);
+ mConfiguredGenerationId = surface.getGenerationId();
}
/**
@@ -129,35 +195,36 @@
*
* @hide
*/
- @SystemApi
- public OutputConfiguration(OutputConfiguration other) {
+ public OutputConfiguration(@NonNull OutputConfiguration other) {
if (other == null) {
throw new IllegalArgumentException("OutputConfiguration shouldn't be null");
}
this.mSurface = other.mSurface;
this.mRotation = other.mRotation;
- this.mSurfaceSetId = other.mSurfaceSetId;
+ this.mSurfaceGroupId = other.mSurfaceGroupId;
this.mConfiguredDataspace = other.mConfiguredDataspace;
this.mConfiguredFormat = other.mConfiguredFormat;
this.mConfiguredSize = other.mConfiguredSize;
+ this.mConfiguredGenerationId = other.mConfiguredGenerationId;
}
/**
* Create an OutputConfiguration from Parcel.
*/
- private OutputConfiguration(Parcel source) {
+ private OutputConfiguration(@NonNull Parcel source) {
int rotation = source.readInt();
int surfaceSetId = source.readInt();
Surface surface = Surface.CREATOR.createFromParcel(source);
checkNotNull(surface, "Surface must not be null");
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
- mSurfaceSetId = surfaceSetId;
+ mSurfaceGroupId = surfaceSetId;
mSurface = surface;
mRotation = rotation;
mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface);
mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface);
mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
+ mConfiguredGenerationId = mSurface.getGenerationId();
}
/**
@@ -165,6 +232,7 @@
*
* @return the {@link Surface} associated with this {@link OutputConfiguration}.
*/
+ @NonNull
public Surface getSurface() {
return mSurface;
}
@@ -183,35 +251,13 @@
}
/**
- * Set the surface set ID to this {@link OutputConfiguration}.
+ * Get the surface group ID associated with this {@link OutputConfiguration}.
*
- * <p>
- * A surface set ID is used to identify which surface set this output surface belongs to. A
- * surface set is a group of output surfaces that are not intended to receive camera output
- * buffer streams simultaneously. The {@link CameraDevice} may be able to share the buffers used
- * by all the surfaces from the same surface set, therefore may save the overall memory
- * footprint. The application should only set the same set ID for the streams that are not
- * simultaneously streaming. A negative ID indicates that this surface doesn't belong to any
- * surface set. The default value will be {@value #SURFACE_SET_ID_INVALID}.
- * </p>
- *
- * @param setId
+ * @return the surface group ID associated with this {@link OutputConfiguration}.
+ * The default value is {@value #SURFACE_GROUP_ID_NONE}.
*/
- public void setSurfaceSetId(int setId) {
- if (setId < 0) {
- setId = SURFACE_SET_ID_INVALID;
- }
- mSurfaceSetId = setId;
- }
-
- /**
- * Get the surface set Id associated with this {@link OutputConfiguration}.
- *
- * @return the surface set Id associated with this {@link OutputConfiguration}.
- * Value will be one of ROTATION_[0, 90, 180, 270]
- */
- public int getSurfaceSetId() {
- return mSurfaceSetId;
+ public int getSurfaceGroupId() {
+ return mSurfaceGroupId;
}
public static final Parcelable.Creator<OutputConfiguration> CREATOR =
@@ -244,7 +290,7 @@
throw new IllegalArgumentException("dest must not be null");
}
dest.writeInt(mRotation);
- dest.writeInt(mSurfaceSetId);
+ dest.writeInt(mSurfaceGroupId);
mSurface.writeToParcel(dest, flags);
}
@@ -265,12 +311,13 @@
return true;
} else if (obj instanceof OutputConfiguration) {
final OutputConfiguration other = (OutputConfiguration) obj;
- return mSurface == other.mSurface &&
- mRotation == other.mRotation &&
+ return mRotation == other.mRotation &&
+ mSurface == other.mSurface &&
+ mConfiguredGenerationId == other.mConfiguredGenerationId &&
mConfiguredSize.equals(other.mConfiguredSize) &&
mConfiguredFormat == other.mConfiguredFormat &&
mConfiguredDataspace == other.mConfiguredDataspace &&
- mSurfaceSetId == other.mSurfaceSetId;
+ mSurfaceGroupId == other.mSurfaceGroupId;
}
return false;
}
@@ -280,16 +327,20 @@
*/
@Override
public int hashCode() {
- return HashCodeHelpers.hashCode(mSurface.hashCode(), mRotation);
+ return HashCodeHelpers.hashCode(
+ mRotation, mSurface.hashCode(), mConfiguredGenerationId,
+ mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace, mSurfaceGroupId);
}
private static final String TAG = "OutputConfiguration";
private final Surface mSurface;
private final int mRotation;
- private int mSurfaceSetId;
+ private int mSurfaceGroupId;
// The size, format, and dataspace of the surface when OutputConfiguration is created.
private final Size mConfiguredSize;
private final int mConfiguredFormat;
private final int mConfiguredDataspace;
+ // Surface generation ID to distinguish changes to Surface native internals
+ private final int mConfiguredGenerationId;
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a025337..5d008e3 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2734,7 +2734,7 @@
private void incCallbackHandlerRefCount() {
synchronized(sCallbackRefCount) {
if (sCallbackRefCount.incrementAndGet() == 1) {
- // TODO - switch this over to a ManagerThread or expire it when done
+ // TODO: switch this to ConnectivityThread
HandlerThread callbackThread = new HandlerThread("ConnectivityManager");
callbackThread.start();
sCallbackHandler = new CallbackHandler(callbackThread.getLooper(),
@@ -3093,6 +3093,10 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+
+ synchronized (sNetworkCallback) {
+ sNetworkCallback.remove(networkCallback.networkRequest);
+ }
}
/**
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 20c2168..2dacf8f 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -120,12 +120,17 @@
* either a bad network configuration (no internet link) or captive portal.
*
* arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK}
+ * obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String}
+ * representing URL that Internet probe was redirect to, if it was redirected,
+ * or mapping to {@code null} otherwise.
*/
public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
public static final int VALID_NETWORK = 1;
public static final int INVALID_NETWORK = 2;
+ public static String REDIRECT_URL_KEY = "redirect URL";
+
/**
* Sent by the NetworkAgent to ConnectivityService to indicate this network was
* explicitly selected. This should be sent before the NetworkInfo is marked
@@ -283,11 +288,12 @@
break;
}
case CMD_REPORT_NETWORK_STATUS: {
+ String redirectUrl = ((Bundle)msg.obj).getString(REDIRECT_URL_KEY);
if (VDBG) {
log("CMD_REPORT_NETWORK_STATUS(" +
- (msg.arg1 == VALID_NETWORK ? "VALID)" : "INVALID)"));
+ (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") + redirectUrl);
}
- networkStatus(msg.arg1);
+ networkStatus(msg.arg1, redirectUrl);
break;
}
case CMD_SAVE_ACCEPT_UNVALIDATED: {
@@ -443,8 +449,12 @@
*
* This may be called multiple times as the network status changes and may
* generate false negatives if we lose ip connectivity before the link is torn down.
+ *
+ * @param status one of {@code VALID_NETWORK} or {@code INVALID_NETWORK}.
+ * @param redirectUrl If the Internet probe was redirected, this is the destination it was
+ * redirected to, otherwise {@code null}.
*/
- protected void networkStatus(int status) {
+ protected void networkStatus(int status, String redirectUrl) {
}
/**
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index cfd0468..1ac9fca 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -228,7 +228,6 @@
* statistics parameters.
*
* @see #setThreadStatsTag(int)
- * @see #setThreadStatsUid(int)
*/
public static void tagSocket(Socket socket) throws SocketException {
SocketTagger.get().tag(socket);
@@ -249,7 +248,6 @@
* parameters.
*
* @see #setThreadStatsTag(int)
- * @see #setThreadStatsUid(int)
*/
public static void tagDatagramSocket(DatagramSocket socket) throws SocketException {
SocketTagger.get().tag(socket);
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index 6729347..87a0b70 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -44,6 +44,7 @@
private final X509TrustManager mTrustManager;
private final Method mCheckServerTrusted;
private final Method mIsUserAddedCertificate;
+ private final Method mIsSameTrustConfiguration;
/**
* Constructs a new X509TrustManagerExtensions wrapper.
@@ -57,6 +58,7 @@
mTrustManager = null;
mCheckServerTrusted = null;
mIsUserAddedCertificate = null;
+ mIsSameTrustConfiguration = null;
return;
}
// Use duck typing if possible.
@@ -80,6 +82,15 @@
throw new IllegalArgumentException(
"Required method isUserAddedCertificate(X509Certificate) missing");
}
+ // Get the option isSameTrustConfiguration method.
+ Method isSameTrustConfiguration = null;
+ try {
+ isSameTrustConfiguration = tm.getClass().getMethod("isSameTrustConfiguration",
+ String.class,
+ String.class);
+ } catch (ReflectiveOperationException ignored) {
+ }
+ mIsSameTrustConfiguration = isSameTrustConfiguration;
}
/**
@@ -150,6 +161,19 @@
*/
@SystemApi
public boolean isSameTrustConfiguration(String hostname1, String hostname2) {
- return true;
+ if (mIsSameTrustConfiguration == null) {
+ return true;
+ }
+ try {
+ return (Boolean) mIsSameTrustConfiguration.invoke(mTrustManager, hostname1, hostname2);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Failed to call isSameTrustConfiguration", e);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ } else {
+ throw new RuntimeException("isSameTrustConfiguration failed", e.getCause());
+ }
+ }
}
}
diff --git a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java b/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
index c6fcb2d..a491ffc 100644
--- a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
+++ b/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
@@ -25,18 +25,40 @@
public class ConnectivityServiceChangeEvent extends IpConnectivityEvent implements Parcelable {
public static final String TAG = "ConnectivityServiceChangeEvent";
- private int mNetId;
+ // The ID of the network that has become the new default or NETID_UNSET if none.
+ private final int mNetId;
+ // The list of transport types of the new default network, for example TRANSPORT_WIFI, as
+ // defined in NetworkCapabilities.java.
+ private final int[] mTransportTypes;
+ // The ID of the network that was the default before or NETID_UNSET if none.
+ private final int mPrevNetId;
+ // Whether the previous network had IPv4/IPv6 connectivity.
+ private final boolean mPrevIPv4;
+ private final boolean mPrevIPv6;
- public ConnectivityServiceChangeEvent(int netId) {
+ public ConnectivityServiceChangeEvent(int netId, int[] transportTypes,
+ int prevNetId, boolean prevIPv4, boolean prevIPv6) {
mNetId = netId;
+ mTransportTypes = transportTypes;
+ mPrevNetId = prevNetId;
+ mPrevIPv4 = prevIPv4;
+ mPrevIPv6 = prevIPv6;
}
public ConnectivityServiceChangeEvent(Parcel in) {
mNetId = in.readInt();
+ mTransportTypes = in.createIntArray();
+ mPrevNetId = in.readInt();
+ mPrevIPv4 = (in.readByte() > 0);
+ mPrevIPv6 = (in.readByte() > 0);
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mNetId);
+ out.writeIntArray(mTransportTypes);
+ out.writeInt(mPrevNetId);
+ out.writeByte(mPrevIPv4 ? (byte) 1 : (byte) 0);
+ out.writeByte(mPrevIPv6 ? (byte) 1 : (byte) 0);
}
public static final Parcelable.Creator<ConnectivityServiceChangeEvent> CREATOR
@@ -50,8 +72,10 @@
}
};
- public static void logEvent(int netId) {
+ public static void logEvent(int netId, int[] transportTypes,
+ int prevNetId, boolean prevIPv4, boolean prevIPv6) {
IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_CONSRV_DEFAULT_NET_CHANGE,
- new ConnectivityServiceChangeEvent(netId));
+ new ConnectivityServiceChangeEvent(
+ netId, transportTypes, prevNetId, prevIPv4, prevIPv6));
}
};
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
new file mode 100644
index 0000000..3869823
--- /dev/null
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide} Event class used to record error events when parsing DHCP response packets.
+ */
+public class DhcpErrorEvent extends IpConnectivityEvent implements Parcelable {
+ public static final String TAG = "DhcpErrorEvent";
+
+ public static final int L2_ERROR = 1;
+ public static final int L3_ERROR = 2;
+ public static final int L4_ERROR = 3;
+ public static final int DHCP_ERROR = 4;
+ public static final int MISC_ERROR = 5;
+
+ public static final int L2_TOO_SHORT = makeErrorCode(L2_ERROR, 1);
+ public static final int L2_WRONG_ETH_TYPE = makeErrorCode(L2_ERROR, 2);
+
+ public static final int L3_TOO_SHORT = makeErrorCode(L3_ERROR, 1);
+ public static final int L3_NOT_IPV4 = makeErrorCode(L3_ERROR, 2);
+ public static final int L3_INVALID_IP = makeErrorCode(L3_ERROR, 3);
+
+ public static final int L4_NOT_UDP = makeErrorCode(L4_ERROR, 1);
+ public static final int L4_WRONG_PORT = makeErrorCode(L4_ERROR, 2);
+
+ public static final int BOOTP_TOO_SHORT = makeErrorCode(DHCP_ERROR, 1);
+ public static final int DHCP_BAD_MAGIC_COOKIE = makeErrorCode(DHCP_ERROR, 2);
+ public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
+ public static final int DHCP_NO_MSG_TYPE = makeErrorCode(DHCP_ERROR, 4);
+ public static final int DHCP_UNKNOWN_MSG_TYPE = makeErrorCode(DHCP_ERROR, 5);
+
+ public static final int BUFFER_UNDERFLOW = makeErrorCode(MISC_ERROR, 1);
+
+ // error code byte format (MSB to LSB):
+ // byte 0: error type
+ // byte 1: error subtype
+ // byte 2: unused
+ // byte 3: optional code
+ public final int errorCode;
+
+ private DhcpErrorEvent(int errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ private DhcpErrorEvent(Parcel in) {
+ this.errorCode = in.readInt();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(errorCode);
+ }
+
+ public static final Parcelable.Creator<DhcpErrorEvent> CREATOR
+ = new Parcelable.Creator<DhcpErrorEvent>() {
+ public DhcpErrorEvent createFromParcel(Parcel in) {
+ return new DhcpErrorEvent(in);
+ }
+
+ public DhcpErrorEvent[] newArray(int size) {
+ return new DhcpErrorEvent[size];
+ }
+ };
+
+ public static void logEvent(int errorCode) {
+ IpConnectivityEvent.logEvent(IPCE_DHCP_PARSE_ERROR, new DhcpErrorEvent(errorCode));
+ }
+
+ public static void logEvent(int errorCode, int option) {
+ logEvent((0xFFFF0000 & errorCode) | (0xFF & option));
+ }
+
+ private static int makeErrorCode(int type, int subtype) {
+ return (type << 24) | ((0xFF & subtype) << 16);
+ }
+}
diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
index ec42890..59c1cfe 100644
--- a/core/java/android/net/metrics/IpConnectivityEvent.java
+++ b/core/java/android/net/metrics/IpConnectivityEvent.java
@@ -28,14 +28,17 @@
// DHCP = DhcpClient
// NETMON = NetworkMonitorEvent
// CONSRV = ConnectivityServiceEvent
+ // IPMGR = IpManager
public static final String TAG = "IpConnectivityEvent";
public static final int IPCE_IPRM_BASE = 0*1024;
public static final int IPCE_DHCP_BASE = 1*1024;
public static final int IPCE_NETMON_BASE = 2*1024;
public static final int IPCE_CONSRV_BASE = 3*1024;
+ public static final int IPCE_IPMGR_BASE = 4*1024;
public static final int IPCE_IPRM_PROBE_RESULT = IPCE_IPRM_BASE + 0;
public static final int IPCE_IPRM_MESSAGE_RECEIVED = IPCE_IPRM_BASE + 1;
+ public static final int IPCE_IPRM_REACHABILITY_LOST = IPCE_IPRM_BASE + 2;
public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0;
public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1;
public static final int IPCE_DHCP_TIMEOUT = IPCE_DHCP_BASE + 2;
@@ -43,6 +46,9 @@
public static final int IPCE_NETMON_STATE_CHANGE = IPCE_NETMON_BASE + 0;
public static final int IPCE_NETMON_CHECK_RESULT = IPCE_NETMON_BASE + 1;
public static final int IPCE_CONSRV_DEFAULT_NET_CHANGE = IPCE_CONSRV_BASE + 0;
+ public static final int IPCE_IPMGR_PROVISIONING_OK = IPCE_IPMGR_BASE + 0;
+ public static final int IPCE_IPMGR_PROVISIONING_FAIL = IPCE_IPMGR_BASE + 1;
+ public static final int IPCE_IPMGR_COMPLETE_LIFECYCLE = IPCE_IPMGR_BASE + 2;
private static ConnectivityMetricsLogger mMetricsLogger = new ConnectivityMetricsLogger();
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
new file mode 100644
index 0000000..6328ccb
--- /dev/null
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class IpManagerEvent extends IpConnectivityEvent implements Parcelable {
+ private String mIfName;
+ private long mDurationMs;
+
+ public IpManagerEvent(String ifName, long duration) {
+ mIfName = ifName;
+ mDurationMs = duration;
+ }
+
+ public IpManagerEvent(Parcel in) {
+ mIfName = in.readString();
+ mDurationMs = in.readLong();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mIfName);
+ out.writeLong(mDurationMs);
+ }
+
+ public static final Parcelable.Creator<IpManagerEvent> CREATOR
+ = new Parcelable.Creator<IpManagerEvent>() {
+ public IpManagerEvent createFromParcel(Parcel in) {
+ return new IpManagerEvent(in);
+ }
+
+ public IpManagerEvent[] newArray(int size) {
+ return new IpManagerEvent[size];
+ }
+ };
+
+ public static void logEvent(int eventType, String ifName, long durationMs) {
+ IpConnectivityEvent.logEvent(eventType, new IpManagerEvent(ifName, durationMs));
+ }
+};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
new file mode 100644
index 0000000..0f14210
--- /dev/null
+++ b/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class IpReachabilityMonitorLostEvent extends IpConnectivityEvent
+ implements Parcelable {
+ private String mIfName;
+
+ public IpReachabilityMonitorLostEvent(String ifName) {
+ mIfName = ifName;
+ }
+
+ public IpReachabilityMonitorLostEvent(Parcel in) {
+ mIfName = in.readString();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mIfName);
+ }
+
+ public static final Parcelable.Creator<IpReachabilityMonitorLostEvent> CREATOR
+ = new Parcelable.Creator<IpReachabilityMonitorLostEvent>() {
+ public IpReachabilityMonitorLostEvent createFromParcel(Parcel in) {
+ return new IpReachabilityMonitorLostEvent(in);
+ }
+
+ public IpReachabilityMonitorLostEvent[] newArray(int size) {
+ return new IpReachabilityMonitorLostEvent[size];
+ }
+ };
+
+ public static void logEvent(String ifName) {
+ IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_IPRM_REACHABILITY_LOST,
+ new IpReachabilityMonitorLostEvent(ifName));
+ }
+};
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index c452837..773e7dd 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -3094,14 +3094,8 @@
dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
u.getWifiControllerActivity(), which);
- // Dump Bluetooth scan data, per UID.
- final long bleScanTimeUs = u.getBluetoothScanTimer().getTotalTimeLocked(
+ dumpTimer(pw, uid, category, BLUETOOTH_MISC_DATA, u.getBluetoothScanTimer(),
rawRealtime, which);
- final int bleScanCount = u.getBluetoothScanTimer().getCountLocked(which);
- if (bleScanTimeUs != 0 || bleScanCount != 0) {
- dumpLine(pw, uid, category, BLUETOOTH_MISC_DATA,
- bleScanTimeUs / 1000, bleScanCount);
- }
dumpControllerActivityLine(pw, uid, category, BLUETOOTH_CONTROLLER_DATA,
u.getBluetoothControllerActivity(), which);
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index ece1228..0a8fdd9 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -824,7 +824,9 @@
}
}
- /** {@hide} */
+ /**
+ * Return the {@link StorageVolume} that contains the given file, or {@code null} if none.
+ */
public @Nullable StorageVolume getStorageVolume(File file) {
return getStorageVolume(getVolumeList(), file);
}
@@ -836,9 +838,13 @@
/** {@hide} */
private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
+ if (file == null) {
+ return null;
+ }
try {
file = file.getCanonicalFile();
} catch (IOException ignored) {
+ Slog.d(TAG, "Could not get canonical path for " + file);
return null;
}
for (StorageVolume volume : volumes) {
@@ -1056,8 +1062,8 @@
}
/**
- * Return if data stored at the given path will be encrypted while at rest.
- * This can help apps avoid the overhead of double-encrypting data.
+ * Return if data stored at or under the given path will be encrypted while
+ * at rest. This can help apps avoid the overhead of double-encrypting data.
*/
public boolean isEncrypted(File file) {
if (FileUtils.contains(Environment.getDataDirectory(), file)) {
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 89ac27c9a..de19f81 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -283,7 +283,7 @@
*
* <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} and above
* and declares as using the {@link android.Manifest.permission#CAMERA} permission which
- * is not granted, then atempting to use this action will result in a {@link
+ * is not granted, then attempting to use this action will result in a {@link
* java.lang.SecurityException}.
*
* @see #EXTRA_OUTPUT
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fdb1cef..788a20c 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -296,7 +296,8 @@
* monitoring of encrypted network traffic.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
- * safeguard against this.
+ * safeguard against this. Add {@link #EXTRA_NUMBER_OF_CERTIFICATES} extra to indicate the
+ * number of certificates.
* <p>
* Input: Nothing.
* <p>
@@ -1369,6 +1370,16 @@
public static final String EXTRA_DO_NOT_DISTURB_MODE_MINUTES =
"android.settings.extra.do_not_disturb_mode_minutes";
+ /**
+ * Activity Extra: Number of certificates
+ * <p>
+ * This can be passed as an extra field to the {@link #ACTION_MONITORING_CERT_INFO}
+ * intent to indicate the number of certificates
+ * @hide
+ */
+ public static final String EXTRA_NUMBER_OF_CERTIFICATES =
+ "android.settings.extra.number_of_certificates";
+
private static final String JID_RESOURCE_PREFIX = "android";
public static final String AUTHORITY = "settings";
@@ -7795,13 +7806,13 @@
* ShortcutManager specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
- * "reset_interval_sec=86400,max_daily_updates=5"
+ * "reset_interval_sec=86400,max_updates_per_interval=1"
*
* The following keys are supported:
*
* <pre>
* reset_interval_sec (long)
- * max_daily_updates (int)
+ * max_updates_per_interval (int)
* max_icon_dimension_dp (int, DP)
* max_icon_dimension_dp_lowram (int, DP)
* max_shortcuts (int)
diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java
index 19f6887..859e022 100644
--- a/core/java/android/security/net/config/RootTrustManager.java
+++ b/core/java/android/security/net/config/RootTrustManager.java
@@ -148,4 +148,15 @@
NetworkSecurityConfig config = mConfig.getConfigForHostname("");
return config.getTrustManager().getAcceptedIssuers();
}
+
+ /**
+ * Returns {@code true} if this trust manager uses the same trust configuration for the provided
+ * hostnames.
+ *
+ * <p>This is required by android.net.http.X509TrustManagerExtensions.
+ */
+ public boolean isSameTrustConfiguration(String hostname1, String hostname2) {
+ return mConfig.getConfigForHostname(hostname1)
+ .equals(mConfig.getConfigForHostname(hostname2));
+ }
}
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index 495fea6..a70c24d 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -105,6 +105,18 @@
out.writeString(mGid2);
}
+ @Override
+ public String toString() {
+ return "CarrierIdentifier{"
+ + "mcc=" + mMcc
+ + ",mnc=" + mMnc
+ + ",spn=" + mSpn
+ + ",imsi=" + mImsi
+ + ",gid1=" + mGid1
+ + ",gid2=" + mGid2
+ + "}";
+ }
+
/** @hide */
public void readFromParcel(Parcel in) {
mMcc = in.readString();
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 1eaa7cf..9b238ce 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -457,8 +457,17 @@
private class SynthHandler extends Handler {
private SpeechItem mCurrentSpeechItem = null;
- private ArrayList<Object> mFlushedObjects = new ArrayList<Object>();
- private boolean mFlushAll;
+ // When a message with QUEUE_FLUSH arrives we add the caller identity to the List and when a
+ // message with QUEUE_DESTROY arrives we increment mFlushAll. Then a message is added to the
+ // handler queue that removes the caller identify from the list and decrements the mFlushAll
+ // counter. This is so that when a message is processed and the caller identity is in the
+ // list or mFlushAll is not zero, we know that the message should be flushed.
+ // It's important that mFlushedObjects is a List and not a Set, and that mFlushAll is an
+ // int and not a bool. This is because when multiple messages arrive with QUEUE_FLUSH or
+ // QUEUE_DESTROY, we want to keep flushing messages until we arrive at the last QUEUE_FLUSH
+ // or QUEUE_DESTROY message.
+ private List<Object> mFlushedObjects = new ArrayList<>();
+ private int mFlushAll = 0;
public SynthHandler(Looper looper) {
super(looper);
@@ -467,7 +476,7 @@
private void startFlushingSpeechItems(Object callerIdentity) {
synchronized (mFlushedObjects) {
if (callerIdentity == null) {
- mFlushAll = true;
+ mFlushAll += 1;
} else {
mFlushedObjects.add(callerIdentity);
}
@@ -476,7 +485,7 @@
private void endFlushingSpeechItems(Object callerIdentity) {
synchronized (mFlushedObjects) {
if (callerIdentity == null) {
- mFlushAll = false;
+ mFlushAll -= 1;
} else {
mFlushedObjects.remove(callerIdentity);
}
@@ -484,7 +493,7 @@
}
private boolean isFlushed(SpeechItem speechItem) {
synchronized (mFlushedObjects) {
- return mFlushAll || mFlushedObjects.contains(speechItem.getCallerIdentity());
+ return mFlushAll > 0 || mFlushedObjects.contains(speechItem.getCallerIdentity());
}
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 94ce57a..239f2d0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -683,7 +683,7 @@
// interface.
int leftLen = mLeftIndents == null ? 0 : mLeftIndents.length;
int rightLen = mRightIndents == null ? 0 : mRightIndents.length;
- int indentsLen = Math.max(1, Math.min(leftLen, rightLen) - mLineCount);
+ int indentsLen = Math.max(1, Math.max(leftLen, rightLen) - mLineCount);
int[] indents = new int[indentsLen];
for (int i = 0; i < indentsLen; i++) {
int leftMargin = mLeftIndents == null ? 0 :
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 3564e11..e93e58d 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -48,6 +48,9 @@
implements KeyListener {
/* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete();
+ private static final int LINE_FEED = 0x0A;
+ private static final int CARRIAGE_RETURN = 0x0D;
+
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -110,34 +113,37 @@
// Initial state
final int STATE_START = 0;
+ // The offset is immediately before line feed.
+ final int STATE_LF = 1;
+
// The offset is immediately before a KEYCAP.
- final int STATE_BEFORE_KEYCAP = 1;
+ final int STATE_BEFORE_KEYCAP = 2;
// The offset is immediately before a variation selector and a KEYCAP.
- final int STATE_BEFORE_VS_AND_KEYCAP = 2;
+ final int STATE_BEFORE_VS_AND_KEYCAP = 3;
// The offset is immediately before an emoji modifier.
- final int STATE_BEFORE_EMOJI_MODIFIER = 3;
+ final int STATE_BEFORE_EMOJI_MODIFIER = 4;
// The offset is immediately before a variation selector and an emoji modifier.
- final int STATE_BEFORE_VS_AND_EMOJI_MODIFIER = 4;
+ final int STATE_BEFORE_VS_AND_EMOJI_MODIFIER = 5;
// The offset is immediately before a variation selector.
- final int STATE_BEFORE_VS = 5;
+ final int STATE_BEFORE_VS = 6;
// The offset is immediately before a ZWJ emoji.
- final int STATE_BEFORE_ZWJ_EMOJI = 6;
+ final int STATE_BEFORE_ZWJ_EMOJI = 7;
// The offset is immediately before a ZWJ that were seen before a ZWJ emoji.
- final int STATE_BEFORE_ZWJ = 7;
+ final int STATE_BEFORE_ZWJ = 8;
// The offset is immediately before a variation selector and a ZWJ that were seen before a
// ZWJ emoji.
- final int STATE_BEFORE_VS_AND_ZWJ = 8;
+ final int STATE_BEFORE_VS_AND_ZWJ = 9;
// The number of following RIS code points is odd.
- final int STATE_ODD_NUMBERED_RIS = 9;
+ final int STATE_ODD_NUMBERED_RIS = 10;
// The number of following RIS code points is even.
- final int STATE_EVEN_NUMBERED_RIS = 10;
+ final int STATE_EVEN_NUMBERED_RIS = 11;
// The state machine has been stopped.
- final int STATE_FINISHED = 11;
+ final int STATE_FINISHED = 12;
int deleteCharCount = 0; // Char count to be deleted by backspace.
int lastSeenVSCharCount = 0; // Char count of previous variation selector.
@@ -152,7 +158,9 @@
switch (state) {
case STATE_START:
deleteCharCount = Character.charCount(codePoint);
- if (isVariationSelector(codePoint)) {
+ if (codePoint == LINE_FEED) {
+ state = STATE_LF;
+ } else if (isVariationSelector(codePoint)) {
state = STATE_BEFORE_VS;
} else if (Emoji.isZwjEmoji(codePoint)) {
state = STATE_BEFORE_ZWJ_EMOJI;
@@ -166,6 +174,11 @@
state = STATE_FINISHED;
}
break;
+ case STATE_LF:
+ if (codePoint == CARRIAGE_RETURN) {
+ ++deleteCharCount;
+ }
+ state = STATE_FINISHED;
case STATE_ODD_NUMBERED_RIS:
if (Emoji.isRegionalIndicatorSymbol(codePoint)) {
deleteCharCount += 2; /* Char count of RIS */
diff --git a/core/java/android/view/IDockedStackListener.aidl b/core/java/android/view/IDockedStackListener.aidl
index cbc8dbd..88ac271 100644
--- a/core/java/android/view/IDockedStackListener.aidl
+++ b/core/java/android/view/IDockedStackListener.aidl
@@ -42,4 +42,9 @@
* @param animDuration The duration of the animation for changing the minimized state.
*/
void onDockedStackMinimizedChanged(boolean minimized, long animDuration);
+
+ /**
+ * Called when window manager repositioned the docked stack after a screen rotation change.
+ */
+ void onDockSideChanged(int newDockSide);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 13712fb..8a6b5da 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10278,7 +10278,8 @@
*/
@Visibility boolean dispatchVisibilityAggregated(boolean isVisible) {
final boolean thisVisible = getVisibility() == VISIBLE;
- if (thisVisible) {
+ // If we're not visible but something is telling us we are, ignore it.
+ if (thisVisible || !isVisible) {
onVisibilityAggregated(isVisible);
}
return thisVisible && isVisible;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a324767..2ce43c8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -549,8 +549,7 @@
// Compute surface insets required to draw at specified Z value.
// TODO: Use real shadow insets for a constant max Z.
if (!attrs.hasManualSurfaceInsets) {
- final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
- attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+ attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
}
CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
@@ -883,10 +882,12 @@
}
mWindowAttributes.privateFlags |= compatibleWindowFlag;
- // Restore old surface insets.
- mWindowAttributes.surfaceInsets.set(
- oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
- mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
+ if (mWindowAttributes.preservePreviousSurfaceInsets) {
+ // Restore old surface insets.
+ mWindowAttributes.surfaceInsets.set(
+ oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
+ mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
+ }
applyKeepScreenOnFlag(mWindowAttributes);
@@ -3373,6 +3374,16 @@
}
@Override
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+ if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
+ // Debugging for b/27963013
+ throw new NullPointerException(
+ "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
+ }
+ return super.sendMessageAtTime(msg, uptimeMillis);
+ }
+
+ @Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_INVALIDATE:
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 584233c..89e146b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1482,6 +1482,16 @@
public boolean hasManualSurfaceInsets;
/**
+ * Whether the previous surface insets should be used vs. what is currently set. When set
+ * to {@code true}, the view root will ignore surfaces insets in this object and use what
+ * it currently has.
+ *
+ * @see #surfaceInsets
+ * @hide
+ */
+ public boolean preservePreviousSurfaceInsets = true;
+
+ /**
* The desired bitmap format. May be one of the constants in
* {@link android.graphics.PixelFormat}. Default is OPAQUE.
*/
@@ -1716,6 +1726,16 @@
*/
public CharSequence accessibilityTitle;
+ /**
+ * Sets a timeout in milliseconds before which the window will be removed
+ * by the window manager. Useful for transient notifications like toasts
+ * so we don't have to rely on client cooperation to ensure the window
+ * is removed. Must be specified at window creation time.
+ *
+ * @hide
+ */
+ public long removeTimeoutMilliseconds = -1;
+
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
@@ -1764,13 +1784,23 @@
title = "";
mTitle = TextUtils.stringOrSpannedString(title);
- accessibilityTitle = mTitle;
}
public final CharSequence getTitle() {
return mTitle != null ? mTitle : "";
}
+ /**
+ * Sets the surface insets based on the elevation (visual z position) of the input view.
+ * @hide
+ */
+ public final void setSurfaceInsets(View view, boolean manual, boolean preservePrevious) {
+ final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
+ surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+ hasManualSurfaceInsets = manual;
+ preservePreviousSurfaceInsets = preservePrevious;
+ }
+
/** @hide */
@SystemApi
public final void setUserActivityTimeout(long timeout) {
@@ -1822,9 +1852,11 @@
out.writeInt(surfaceInsets.right);
out.writeInt(surfaceInsets.bottom);
out.writeInt(hasManualSurfaceInsets ? 1 : 0);
+ out.writeInt(preservePreviousSurfaceInsets ? 1 : 0);
out.writeInt(needsMenuKey);
out.writeInt(accessibilityIdOfAnchor);
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
+ out.writeLong(removeTimeoutMilliseconds);
}
public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1874,9 +1906,11 @@
surfaceInsets.right = in.readInt();
surfaceInsets.bottom = in.readInt();
hasManualSurfaceInsets = in.readInt() != 0;
+ preservePreviousSurfaceInsets = in.readInt() != 0;
needsMenuKey = in.readInt();
accessibilityIdOfAnchor = in.readInt();
accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ removeTimeoutMilliseconds = in.readLong();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -2075,6 +2109,11 @@
changes |= SURFACE_INSETS_CHANGED;
}
+ if (preservePreviousSurfaceInsets != o.preservePreviousSurfaceInsets) {
+ preservePreviousSurfaceInsets = o.preservePreviousSurfaceInsets;
+ changes |= SURFACE_INSETS_CHANGED;
+ }
+
if (needsMenuKey != o.needsMenuKey) {
needsMenuKey = o.needsMenuKey;
changes |= NEEDS_MENU_KEY_CHANGED;
@@ -2092,6 +2131,9 @@
changes |= ACCESSIBILITY_TITLE_CHANGED;
}
+ // This can't change, it's only set at window creation time.
+ removeTimeoutMilliseconds = o.removeTimeoutMilliseconds;
+
return changes;
}
@@ -2200,11 +2242,15 @@
sb.append(" userActivityTimeout=").append(userActivityTimeout);
}
if (surfaceInsets.left != 0 || surfaceInsets.top != 0 || surfaceInsets.right != 0 ||
- surfaceInsets.bottom != 0 || hasManualSurfaceInsets) {
+ surfaceInsets.bottom != 0 || hasManualSurfaceInsets
+ || !preservePreviousSurfaceInsets) {
sb.append(" surfaceInsets=").append(surfaceInsets);
if (hasManualSurfaceInsets) {
sb.append(" (manual)");
}
+ if (!preservePreviousSurfaceInsets) {
+ sb.append(" (!preservePreviousSurfaceInsets)");
+ }
}
if (needsMenuKey != NEEDS_MENU_UNSET) {
sb.append(" needsMenuKey=");
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 02d2a8b..c1076e7 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3842,7 +3842,15 @@
*/
public static RangeInfo obtain(int type, float min, float max, float current) {
RangeInfo info = sPool.acquire();
- return (info != null) ? info : new RangeInfo(type, min, max, current);
+ if (info == null) {
+ return new RangeInfo(type, min, max, current);
+ }
+
+ info.mType = type;
+ info.mMin = min;
+ info.mMax = max;
+ info.mCurrent = current;
+ return info;
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index dc433b1..dc4db01 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -20,6 +20,9 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.icu.text.DisplayContext;
+import android.icu.text.LocaleDisplayNames;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -421,39 +424,97 @@
}
/**
- * @param context Context will be used for getting Locale and PackageManager.
- * @param packageName The package name of the IME
- * @param appInfo The application info of the IME
- * @return a display name for this subtype. The string resource of the label (mSubtypeNameResId)
- * may have exactly one %s in it. If there is, the %s part will be replaced with the locale's
- * display name by the formatter. If there is not, this method returns the string specified by
- * mSubtypeNameResId. If mSubtypeNameResId is not specified (== 0), it's up to the framework to
- * generate an appropriate display name.
+ * Returns a display name for this subtype.
+ *
+ * <p>If {@code subtypeNameResId} is specified (!= 0) text generated from that resource will
+ * be returned. The localized string resource of the label should be capitalized for inclusion
+ * in UI lists. The string resource may contain at most one {@code %s}. If present, the
+ * {@code %s} will be replaced with the display name of the subtype locale in the user's locale.
+ *
+ * <p>If {@code subtypeNameResId} is not specified (== 0) the framework returns the display name
+ * of the subtype locale, as capitalized for use in UI lists, in the user's locale.
+ *
+ * @param context {@link Context} will be used for getting {@link Locale} and
+ * {@link android.content.pm.PackageManager}.
+ * @param packageName The package name of the input method.
+ * @param appInfo The {@link ApplicationInfo} of the input method.
+ * @return a display name for this subtype.
*/
+ @NonNull
public CharSequence getDisplayName(
Context context, String packageName, ApplicationInfo appInfo) {
- final Locale locale = getLocaleObject();
- final String localeStr = locale != null ? locale.getDisplayName() : mSubtypeLocale;
if (mSubtypeNameResId == 0) {
- return localeStr;
+ return getLocaleDisplayName(getLocaleFromContext(context), getLocaleObject(),
+ DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU);
}
+
final CharSequence subtypeName = context.getPackageManager().getText(
packageName, mSubtypeNameResId, appInfo);
- if (!TextUtils.isEmpty(subtypeName)) {
- final String replacementString =
- containsExtraValueKey(EXTRA_KEY_UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)
- ? getExtraValueOf(EXTRA_KEY_UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)
- : localeStr;
- try {
- return String.format(
- subtypeName.toString(), replacementString != null ? replacementString : "");
- } catch (IllegalFormatException e) {
- Slog.w(TAG, "Found illegal format in subtype name("+ subtypeName + "): " + e);
- return "";
- }
- } else {
- return localeStr;
+ if (TextUtils.isEmpty(subtypeName)) {
+ return "";
}
+ final String subtypeNameString = subtypeName.toString();
+ String replacementString;
+ if (containsExtraValueKey(EXTRA_KEY_UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)) {
+ replacementString = getExtraValueOf(
+ EXTRA_KEY_UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME);
+ } else {
+ final DisplayContext displayContext;
+ if (TextUtils.equals(subtypeNameString, "%s")) {
+ displayContext = DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU;
+ } else if (subtypeNameString.startsWith("%s")) {
+ displayContext = DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE;
+ } else {
+ displayContext = DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE;
+ }
+ replacementString = getLocaleDisplayName(getLocaleFromContext(context),
+ getLocaleObject(), displayContext);
+ }
+ if (replacementString == null) {
+ replacementString = "";
+ }
+ try {
+ return String.format(subtypeNameString, replacementString);
+ } catch (IllegalFormatException e) {
+ Slog.w(TAG, "Found illegal format in subtype name("+ subtypeName + "): " + e);
+ return "";
+ }
+ }
+
+ @Nullable
+ private static Locale getLocaleFromContext(@Nullable final Context context) {
+ if (context == null) {
+ return null;
+ }
+ if (context.getResources() == null) {
+ return null;
+ }
+ final Configuration configuration = context.getResources().getConfiguration();
+ if (configuration == null) {
+ return null;
+ }
+ return configuration.getLocales().get(0);
+ }
+
+ /**
+ * @param displayLocale {@link Locale} to be used to display {@code localeToDisplay}
+ * @param localeToDisplay {@link Locale} to be displayed in {@code displayLocale}
+ * @param displayContext context parameter to be used to display {@code localeToDisplay} in
+ * {@code displayLocale}
+ * @return Returns the name of the {@code localeToDisplay} in the user's current locale.
+ */
+ @NonNull
+ private static String getLocaleDisplayName(
+ @Nullable Locale displayLocale, @Nullable Locale localeToDisplay,
+ final DisplayContext displayContext) {
+ if (localeToDisplay == null) {
+ return "";
+ }
+ final Locale nonNullDisplayLocale =
+ displayLocale != null ? displayLocale : Locale.getDefault();
+ return LocaleDisplayNames
+ .getInstance(nonNullDisplayLocale, displayContext)
+ .localeDisplayName(localeToDisplay);
}
private HashMap<String, String> getExtraValueHashMap() {
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 0ac5731..f13cbae 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -18,13 +18,14 @@
import android.annotation.SystemApi;
import android.app.ActivityManagerInternal;
+import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.res.XmlResourceParser;
+import android.content.pm.Signature;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
@@ -32,27 +33,21 @@
import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.Trace;
-import android.provider.Settings;
-import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
+import android.util.ArraySet;
import android.util.Log;
-import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
import dalvik.system.VMRuntime;
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-import org.xmlpull.v1.XmlPullParserException;
-
/**
* Top level factory, used creating all the main WebView implementation classes.
*
@@ -192,52 +187,126 @@
}
}
+ /**
+ * Returns true if the signatures match, false otherwise
+ */
+ private static boolean signaturesEquals(Signature[] s1, Signature[] s2) {
+ if (s1 == null) {
+ return s2 == null;
+ }
+ if (s2 == null) return false;
+
+ ArraySet<Signature> set1 = new ArraySet<>();
+ for(Signature signature : s1) {
+ set1.add(signature);
+ }
+ ArraySet<Signature> set2 = new ArraySet<>();
+ for(Signature signature : s2) {
+ set2.add(signature);
+ }
+ return set1.equals(set2);
+ }
+
+ // Throws MissingWebViewPackageException on failure
+ private static void verifyPackageInfo(PackageInfo chosen, PackageInfo toUse) {
+ if (!chosen.packageName.equals(toUse.packageName)) {
+ throw new MissingWebViewPackageException("Failed to verify WebView provider, "
+ + "packageName mismatch, expected: "
+ + chosen.packageName + " actual: " + toUse.packageName);
+ }
+ if (chosen.versionCode > toUse.versionCode) {
+ throw new MissingWebViewPackageException("Failed to verify WebView provider, "
+ + "version code mismatch, expected: " + chosen.versionCode
+ + " actual: " + toUse.versionCode);
+ }
+ if (getWebViewLibrary(toUse.applicationInfo) == null) {
+ throw new MissingWebViewPackageException("Tried to load an invalid WebView provider: "
+ + toUse.packageName);
+ }
+ if (!signaturesEquals(chosen.signatures, toUse.signatures)) {
+ throw new MissingWebViewPackageException("Failed to verify WebView provider, "
+ + "signature mismatch");
+ }
+ }
+
+ private static Context getWebViewContextAndSetProvider() {
+ Application initialApplication = AppGlobals.getInitialApplication();
+ try {
+ WebViewProviderResponse response = null;
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
+ "WebViewUpdateService.waitForAndGetProvider()");
+ try {
+ response = getUpdateService().waitForAndGetProvider();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ }
+ if (response.status != LIBLOAD_SUCCESS) {
+ throw new MissingWebViewPackageException("Failed to load WebView provider: "
+ + getWebViewPreparationErrorReason(response.status));
+ }
+ // Register to be killed before fetching package info - so that we will be
+ // killed if the package info goes out-of-date.
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "ActivityManager.addPackageDependency()");
+ try {
+ ActivityManagerNative.getDefault().addPackageDependency(
+ response.packageInfo.packageName);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ }
+ // Fetch package info and verify it against the chosen package
+ PackageInfo newPackageInfo = null;
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getPackageInfo()");
+ try {
+ newPackageInfo = initialApplication.getPackageManager().getPackageInfo(
+ response.packageInfo.packageName,
+ PackageManager.GET_SHARED_LIBRARY_FILES
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
+ // Make sure that we fetch the current provider even if its not
+ // installed for the current user
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES
+ // Fetch signatures for verification
+ | PackageManager.GET_SIGNATURES
+ // Get meta-data for meta data flag verification
+ | PackageManager.GET_META_DATA);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ }
+
+ // Validate the newly fetched package info, throws MissingWebViewPackageException on
+ // failure
+ verifyPackageInfo(response.packageInfo, newPackageInfo);
+
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
+ "initialApplication.createApplicationContext");
+ try {
+ // Construct an app context to load the Java code into the current app.
+ Context webViewContext = initialApplication.createApplicationContext(
+ newPackageInfo.applicationInfo,
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ sPackageInfo = response.packageInfo;
+ return webViewContext;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ }
+ } catch (RemoteException | PackageManager.NameNotFoundException e) {
+ throw new MissingWebViewPackageException("Failed to load WebView provider: " + e);
+ }
+ }
+
private static Class<WebViewFactoryProvider> getProviderClass() {
+ Context webViewContext = null;
+ Application initialApplication = AppGlobals.getInitialApplication();
+
try {
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
- "WebViewFactory.waitForProviderAndSetPackageInfo()");
+ "WebViewFactory.getWebViewContextAndSetProvider()");
try {
- // First fetch the package info so we can log the webview package version.
- int res = waitForProviderAndSetPackageInfo();
- if (res != LIBLOAD_SUCCESS) {
- throw new MissingWebViewPackageException(
- "Failed to load WebView provider, error: "
- + getWebViewPreparationErrorReason(res));
- }
+ webViewContext = getWebViewContextAndSetProvider();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
- sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
-
- Application initialApplication = AppGlobals.getInitialApplication();
- Context webViewContext = null;
- Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getApplicationInfo()");
- try {
- // Construct a package context to load the Java code into the current app.
- // This is done as early as possible since by constructing a package context we
- // register the WebView package as a dependency for the current application so that
- // when the WebView package is updated this application will be killed.
- ApplicationInfo applicationInfo =
- initialApplication.getPackageManager().getApplicationInfo(
- sPackageInfo.packageName, PackageManager.GET_SHARED_LIBRARY_FILES
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
- // make sure that we fetch the current provider even if its not installed
- // for the current user
- | PackageManager.MATCH_UNINSTALLED_PACKAGES);
- Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
- "initialApplication.createApplicationContext");
- try {
- webViewContext = initialApplication.createApplicationContext(applicationInfo,
- Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
- }
- } catch (PackageManager.NameNotFoundException e) {
- throw new MissingWebViewPackageException(e);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
- }
+ sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 0d8d8ed..af46756 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1290,9 +1290,7 @@
// We may wrap that in another view, so we'll need to manually specify
// the surface insets.
- final int surfaceInset = (int) Math.ceil(mBackgroundView.getZ() * 2);
- p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
- p.hasManualSurfaceInsets = true;
+ p.setSurfaceInsets(mBackgroundView, true /*manual*/, true /*preservePrevious*/);
mPopupViewInitialLayoutDirectionInherited =
(mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
@@ -1581,7 +1579,7 @@
return true;
}
- final int spaceAbove = displayFrameTop + anchorTopInScreen - anchorHeight;
+ final int spaceAbove = anchorTopInScreen - anchorHeight - displayFrameTop;
if (height <= spaceAbove) {
// Move everything up.
if (mOverlapAnchor) {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index e9fa26c..9c9784b 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1347,6 +1347,13 @@
if (d instanceof LayerDrawable) {
d = ((LayerDrawable) d).findDrawableByLayerId(id);
+ if (d == null) {
+ // If we can't find the requested layer, fall back to setting
+ // the level of the entire drawable. This will break if
+ // progress is set on multiple elements, but the theme-default
+ // drawable will always have all layer IDs present.
+ d = mCurrentDrawable;
+ }
}
if (d != null) {
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 7220256..24d2c8e 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -58,8 +58,8 @@
private static final String TAG = "RadialTimePickerView";
- private static final int HOURS = 0;
- private static final int MINUTES = 1;
+ public static final int HOURS = 0;
+ public static final int MINUTES = 1;
private static final int HOURS_INNER = 2;
private static final int SELECTOR_CIRCLE = 0;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 6d2cea6..a9b7f4e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1856,6 +1856,7 @@
public static final int LAYOUT_MARGIN_END = 1;
/** Set width */
public static final int LAYOUT_WIDTH = 2;
+ public static final int LAYOUT_MARGIN_BOTTOM = 3;
/**
* @param viewId ID of the view alter
@@ -1898,6 +1899,12 @@
target.setLayoutParams(layoutParams);
}
break;
+ case LAYOUT_MARGIN_BOTTOM:
+ if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
+ ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = value;
+ target.setLayoutParams(layoutParams);
+ }
+ break;
case LAYOUT_WIDTH:
layoutParams.width = value;
target.setLayoutParams(layoutParams);
@@ -2870,6 +2877,16 @@
}
/**
+ * Equivalent to setting {@link android.view.ViewGroup.MarginLayoutParams#bottomMargin}.
+ *
+ * @hide
+ */
+ public void setViewLayoutMarginBottom(int viewId, int bottomMargin) {
+ addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_BOTTOM,
+ bottomMargin));
+ }
+
+ /**
* Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width}.
* @hide
*/
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index ee716df..1a81d20 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -849,10 +849,12 @@
mEnabledDayStart = MathUtils.constrain(enabledDayStart, 1, mDaysInMonth);
mEnabledDayEnd = MathUtils.constrain(enabledDayEnd, mEnabledDayStart, mDaysInMonth);
+ updateMonthYearLabel();
+ updateDayOfWeekLabels();
+
// Invalidate cached accessibility information.
mTouchHelper.invalidateRoot();
-
- updateMonthYearLabel();
+ invalidate();
if (DEBUG_WRONG_DATE) {
Log.d(LOG_TAG, "mMonth = " + mMonth);
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 4a24e26..0c3892d 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -58,8 +58,8 @@
private static final long DELAY_COMMIT_MILLIS = 2000;
// Index used by RadialPickerLayout
- private static final int HOUR_INDEX = 0;
- private static final int MINUTE_INDEX = 1;
+ private static final int HOUR_INDEX = RadialTimePickerView.HOURS;
+ private static final int MINUTE_INDEX = RadialTimePickerView.MINUTES;
// NOT a real index for the purpose of what's showing.
private static final int AMPM_INDEX = 2;
@@ -82,6 +82,10 @@
private final Calendar mTempCalendar;
+ // Accessibility strings.
+ private final String mSelectHours;
+ private final String mSelectMinutes;
+
private boolean mIsEnabled = true;
private boolean mAllowAutoAdvance;
private int mInitialHourOfDay;
@@ -89,10 +93,6 @@
private boolean mIs24Hour;
private boolean mIsAmPmAtStart;
- // Accessibility strings.
- private String mSelectHours;
- private String mSelectMinutes;
-
// Localization data.
private boolean mHourFormatShowLeadingZero;
private boolean mHourFormatStartsAtZero;
@@ -520,11 +520,15 @@
} else {
flags |= DateUtils.FORMAT_12HOUR;
}
+
mTempCalendar.set(Calendar.HOUR_OF_DAY, getHour());
mTempCalendar.set(Calendar.MINUTE, getMinute());
- String selectedDate = DateUtils.formatDateTime(mContext,
+
+ final String selectedTime = DateUtils.formatDateTime(mContext,
mTempCalendar.getTimeInMillis(), flags);
- event.getText().add(selectedDate);
+ final String selectionMode = mRadialTimePickerView.getCurrentItemShowing() == HOUR_INDEX ?
+ mSelectHours : mSelectMinutes;
+ event.getText().add(selectedTime + " " + selectionMode);
}
/**
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 207f675..7762675 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -163,6 +163,7 @@
*/
public void setDuration(@Duration int duration) {
mDuration = duration;
+ mTN.mDuration = duration;
}
/**
@@ -342,7 +343,7 @@
};
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
- final Handler mHandler = new Handler();
+ final Handler mHandler = new Handler();
int mGravity;
int mX, mY;
@@ -352,9 +353,13 @@
View mView;
View mNextView;
+ int mDuration;
WindowManager mWM;
+ static final long SHORT_DURATION_TIMEOUT = 5000;
+ static final long LONG_DURATION_TIMEOUT = 1000;
+
TN() {
// XXX This should be changed to use a Dialog, with a Theme.Toast
// defined that sets up the layout params appropriately.
@@ -417,6 +422,8 @@
mParams.verticalMargin = mVerticalMargin;
mParams.horizontalMargin = mHorizontalMargin;
mParams.packageName = packageName;
+ mParams.removeTimeoutMilliseconds = mDuration ==
+ Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
if (mView.getParent() != null) {
if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 1f2acc9..085e159 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -16,7 +16,9 @@
package com.android.internal.app;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.VoiceInteractor.PickOptionRequest;
@@ -24,6 +26,7 @@
import android.app.VoiceInteractor.Prompt;
import android.content.pm.ComponentInfo;
import android.os.AsyncTask;
+import android.provider.MediaStore;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
@@ -119,37 +122,62 @@
}
};
+ /**
+ * Get the string resource to be used as a label for the link to the resolver activity for an
+ * action.
+ *
+ * @param action The action to resolve
+ *
+ * @return The string resource to be used as a label
+ */
+ public static @StringRes int getLabelRes(String action) {
+ return ActionTitle.forAction(action).labelRes;
+ }
+
private enum ActionTitle {
VIEW(Intent.ACTION_VIEW,
com.android.internal.R.string.whichViewApplication,
- com.android.internal.R.string.whichViewApplicationNamed),
+ com.android.internal.R.string.whichViewApplicationNamed,
+ com.android.internal.R.string.whichViewApplicationLabel),
EDIT(Intent.ACTION_EDIT,
com.android.internal.R.string.whichEditApplication,
- com.android.internal.R.string.whichEditApplicationNamed),
+ com.android.internal.R.string.whichEditApplicationNamed,
+ com.android.internal.R.string.whichEditApplicationLabel),
SEND(Intent.ACTION_SEND,
com.android.internal.R.string.whichSendApplication,
- com.android.internal.R.string.whichSendApplicationNamed),
+ com.android.internal.R.string.whichSendApplicationNamed,
+ com.android.internal.R.string.whichSendApplicationLabel),
SENDTO(Intent.ACTION_SENDTO,
com.android.internal.R.string.whichSendToApplication,
- com.android.internal.R.string.whichSendToApplicationNamed),
+ com.android.internal.R.string.whichSendToApplicationNamed,
+ com.android.internal.R.string.whichSendToApplicationLabel),
SEND_MULTIPLE(Intent.ACTION_SEND_MULTIPLE,
com.android.internal.R.string.whichSendApplication,
- com.android.internal.R.string.whichSendApplicationNamed),
+ com.android.internal.R.string.whichSendApplicationNamed,
+ com.android.internal.R.string.whichSendApplicationLabel),
+ CAPTURE_IMAGE(MediaStore.ACTION_IMAGE_CAPTURE,
+ com.android.internal.R.string.whichImageCaptureApplication,
+ com.android.internal.R.string.whichImageCaptureApplicationNamed,
+ com.android.internal.R.string.whichImageCaptureApplicationLabel),
DEFAULT(null,
com.android.internal.R.string.whichApplication,
- com.android.internal.R.string.whichApplicationNamed),
+ com.android.internal.R.string.whichApplicationNamed,
+ com.android.internal.R.string.whichApplicationLabel),
HOME(Intent.ACTION_MAIN,
com.android.internal.R.string.whichHomeApplication,
- com.android.internal.R.string.whichHomeApplicationNamed);
+ com.android.internal.R.string.whichHomeApplicationNamed,
+ com.android.internal.R.string.whichHomeApplicationLabel);
public final String action;
public final int titleRes;
public final int namedTitleRes;
+ public final @StringRes int labelRes;
- ActionTitle(String action, int titleRes, int namedTitleRes) {
+ ActionTitle(String action, int titleRes, int namedTitleRes, @StringRes int labelRes) {
this.action = action;
this.titleRes = titleRes;
this.namedTitleRes = namedTitleRes;
+ this.labelRes = labelRes;
}
public static ActionTitle forAction(String action) {
@@ -640,12 +668,19 @@
&& mAdapter.mOrigResolveList != null) {
// Build a reasonable intent filter, based on what matched.
IntentFilter filter = new IntentFilter();
- String action = intent.getAction();
+ Intent filterIntent;
+ if (intent.getSelector() != null) {
+ filterIntent = intent.getSelector();
+ } else {
+ filterIntent = intent;
+ }
+
+ String action = filterIntent.getAction();
if (action != null) {
filter.addAction(action);
}
- Set<String> categories = intent.getCategories();
+ Set<String> categories = filterIntent.getCategories();
if (categories != null) {
for (String cat : categories) {
filter.addCategory(cat);
@@ -654,9 +689,9 @@
filter.addCategory(Intent.CATEGORY_DEFAULT);
int cat = ri.match & IntentFilter.MATCH_CATEGORY_MASK;
- Uri data = intent.getData();
+ Uri data = filterIntent.getData();
if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
- String mimeType = intent.resolveType(this);
+ String mimeType = filterIntent.resolveType(this);
if (mimeType != null) {
try {
filter.addDataType(mimeType);
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 06542f7..2f80b86 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -516,7 +516,7 @@
out.writeInt((int)val);
} else {
int top = ~((int)((val>>32)&0x7fffffff));
- int bottom = (int)(val&0xfffffff);
+ int bottom = (int)(val&0x0ffffffffL);
out.writeInt(top);
out.writeInt(bottom);
}
diff --git a/core/java/com/android/internal/app/procstats/SparseMappingTable.java b/core/java/com/android/internal/app/procstats/SparseMappingTable.java
index 76102af..f941836 100644
--- a/core/java/com/android/internal/app/procstats/SparseMappingTable.java
+++ b/core/java/com/android/internal/app/procstats/SparseMappingTable.java
@@ -68,11 +68,8 @@
* A table of data as stored in a SparseMappingTable.
*/
public static class Table {
- // When mSequence is this this our data better be empty
- private static final int UNINITIALIZED_SEQUENCE = -1;
-
private SparseMappingTable mParent;
- private int mSequence = UNINITIALIZED_SEQUENCE;
+ private int mSequence = 1;
private int[] mTable;
private int mSize;
@@ -119,12 +116,6 @@
* but should be considered opaque to the caller.
*/
public int getOrAddKey(byte id, int count) {
- // This is the only place we add data to mParent.mLongs, so this is the time
- // to update our sequence to match there.
- if (mSequence == UNINITIALIZED_SEQUENCE) {
- mSequence = mParent.mSequence;
- }
-
assertConsistency();
final int idx = binarySearch(id);
@@ -311,7 +302,7 @@
// Reset our sequence number. This will make all read/write calls
// start to fail, and then when we re-allocate it will be re-synced
// to that of mParent.
- mSequence = UNINITIALIZED_SEQUENCE;
+ mSequence = mParent.mSequence;
}
/**
@@ -377,27 +368,19 @@
// Original bug: b/27045736
// New bug: b/27960286
if (false) {
- // Assert that our sequence number has been initialized. If it hasn't
- // that means someone tried to read or write data without allocating it
- // since we were created or reset.
- if (mSequence == UNINITIALIZED_SEQUENCE) {
- logOrThrow("mSequence == UNINITIALIZED_SEQUENCE in"
- + " SparseMappingTable.Table. -- "
- + dumpInternalState());
- return;
- }
-
// Assert that our sequence number matches mParent's. If it isn't that means
- // we have been reset and our
+ // we have been reset and our. If our sequence is UNITIALIZED_SEQUENCE, then
+ // it's possible that everything is working fine and we just haven't been
+ // written to since the last resetTable().
if (mSequence != mParent.mSequence) {
if (mSequence < mParent.mSequence) {
- logOrThrow("Sequence mismatch. SparseMappingTable.resetTable()"
+ logOrThrow("Sequence mismatch. SparseMappingTable.reset()"
+ " called but not Table.resetTable() -- "
+ dumpInternalState());
return;
} else if (mSequence > mParent.mSequence) {
logOrThrow("Sequence mismatch. Table.resetTable()"
- + " called but not SparseMappingTable.resetTable() -- "
+ + " called but not SparseMappingTable.reset() -- "
+ dumpInternalState());
return;
}
@@ -494,6 +477,10 @@
}
}
+ public SparseMappingTable() {
+ mLongs.add(new long[ARRAY_SIZE]);
+ }
+
/**
* Wipe out all the data.
*/
@@ -545,6 +532,35 @@
}
/**
+ * Return a string for debugging.
+ */
+ public String dumpInternalState(boolean includeData) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SparseMappingTable{");
+ sb.append("mSequence=");
+ sb.append(mSequence);
+ sb.append(" mNextIndex=");
+ sb.append(mNextIndex);
+ sb.append(" mLongs.size=");
+ final int N = mLongs.size();
+ sb.append(N);
+ sb.append("\n");
+ if (includeData) {
+ for (int i=0; i<N; i++) {
+ final long[] array = mLongs.get(i);
+ for (int j=0; j<array.length; j++) {
+ if (i == N-1 && j == mNextIndex) {
+ break;
+ }
+ sb.append(String.format(" %4d %d 0x%016x %-19d\n", i, j, array[j], array[j]));
+ }
+ }
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
* Write the long array to the parcel in a compacted form. Does not allow negative
* values in the array.
*/
@@ -559,7 +575,7 @@
out.writeInt((int)val);
} else {
int top = ~((int)((val>>32)&0x7fffffff));
- int bottom = (int)(val&0xfffffff);
+ int bottom = (int)(val&0x0ffffffffL);
out.writeInt(top);
out.writeInt(bottom);
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5980ab6..78b5d61 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -43,6 +43,7 @@
import dalvik.system.DexFile;
import dalvik.system.PathClassLoader;
import dalvik.system.VMRuntime;
+import dalvik.system.ZygoteHooks;
import libcore.io.IoUtils;
@@ -597,6 +598,10 @@
}
public static void main(String argv[]) {
+ // Mark zygote start. This ensures that thread creation will throw
+ // an error.
+ ZygoteHooks.startZygoteNoThreadCreation();
+
try {
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
RuntimeInit.enableDdms();
@@ -648,6 +653,8 @@
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
+ ZygoteHooks.stopZygoteNoThreadCreation();
+
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index f9ac563..3aa7719 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -210,7 +210,6 @@
private Drawable mResizingBackgroundDrawable;
private Drawable mCaptionBackgroundDrawable;
private Drawable mUserCaptionBackgroundDrawable;
- private Drawable mOriginalBackgroundDrawable;
private float mAvailableWidth;
@@ -891,11 +890,6 @@
mBackgroundPadding.setEmpty();
}
drawableChanged();
-
- // Make sure we don't reset to the old drawable when finishing resizing.
- if (mResizeMode != RESIZE_MODE_INVALID) {
- mOriginalBackgroundDrawable = null;
- }
}
}
@@ -1960,9 +1954,6 @@
updateElevation();
updateColorViews(null /* insets */, false);
-
- mOriginalBackgroundDrawable = getBackground();
- setBackgroundDrawable(null);
}
mResizeMode = resizeMode;
getViewRootImpl().requestInvalidateRootRenderNode();
@@ -1974,10 +1965,6 @@
updateColorViews(null /* insets */, false);
mResizeMode = RESIZE_MODE_INVALID;
getViewRootImpl().requestInvalidateRootRenderNode();
- if (mOriginalBackgroundDrawable != null) {
- setBackgroundDrawable(mOriginalBackgroundDrawable);
- mOriginalBackgroundDrawable = null;
- }
}
@Override
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index d2ff9bc..fe63267 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -1403,10 +1403,12 @@
@Override
public final void setElevation(float elevation) {
mElevation = elevation;
+ final WindowManager.LayoutParams attrs = getAttributes();
if (mDecor != null) {
mDecor.setElevation(elevation);
+ attrs.setSurfaceInsets(mDecor, true /*manual*/, false /*preservePrevious*/);
}
- dispatchWindowAttributesChanged(getAttributes());
+ dispatchWindowAttributesChanged(attrs);
}
@Override
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 21c4d12..b2fc2bb 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -43,4 +43,5 @@
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
void requireStrongAuth(int strongAuthReason, int userId);
void systemReady();
+ void userPresent(int userId);
}
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index 78c5e34..e2d8ffc 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -16,13 +16,18 @@
package com.android.internal.widget;
+import com.android.internal.R;
+
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.text.BoringLayout;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.view.RemotableViewMethod;
import android.widget.RemoteViews;
import android.widget.TextView;
@@ -35,7 +40,8 @@
@RemoteViews.RemoteView
public class ImageFloatingTextView extends TextView {
- private boolean mHasImage;
+ /** Number of lines from the top to indent */
+ private int mIndentLines;
public ImageFloatingTextView(Context context) {
this(context, null);
@@ -69,10 +75,16 @@
.setEllipsizedWidth(ellipsisWidth)
.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
- // we set the endmargin on the first 2 lines. this works just in our case but that's
- // sufficient for now.
- int endMargin = (int) (getResources().getDisplayMetrics().density * 52);
- int[] margins = mHasImage ? new int[] {endMargin, endMargin, 0} : null;
+ // we set the endmargin on the requested number of lines.
+ int endMargin = getContext().getResources().getDimensionPixelSize(
+ R.dimen.notification_content_picture_margin);
+ int[] margins = null;
+ if (mIndentLines > 0) {
+ margins = new int[mIndentLines + 1];
+ for (int i = 0; i < mIndentLines; i++) {
+ margins[i] = endMargin;
+ }
+ }
if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
builder.setIndents(margins, null);
} else {
@@ -84,8 +96,22 @@
@RemotableViewMethod
public void setHasImage(boolean hasImage) {
- mHasImage = hasImage;
+ mIndentLines = hasImage ? 2 : 0;
// The new layout will be automatically created when the text is
// set again by the notification.
}
+
+ /**
+ * @param lines the number of lines at the top that should be indented by indentEnd
+ * @return whether a change was made
+ */
+ public boolean setNumIndentLines(int lines) {
+ if (mIndentLines != lines) {
+ mIndentLines = lines;
+ // Invalidate layout.
+ setHint(getHint());
+ return true;
+ }
+ return false;
+ }
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index bceeaca..d9b6329 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -172,6 +172,14 @@
}
}
+ public void userPresent(int userId) {
+ try {
+ getLockSettings().userPresent(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
public static final class RequestThrottledException extends Exception {
private int mTimeoutMs;
public RequestThrottledException(int timeoutMs) {
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
new file mode 100644
index 0000000..dc7b7f5
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -0,0 +1,278 @@
+/*
+ * 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
+ */
+
+package com.android.internal.widget;
+
+import com.android.internal.R;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.RemotableViewMethod;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RemoteViews;
+
+/**
+ * A custom-built layout for the Notification.MessagingStyle.
+ *
+ * Evicts children until they all fit.
+ */
+@RemoteViews.RemoteView
+public class MessagingLinearLayout extends ViewGroup {
+
+ /**
+ * Spacing to be applied between views.
+ */
+ private int mSpacing;
+
+ /**
+ * The maximum height allowed.
+ */
+ private int mMaxHeight;
+
+ private int mIndentLines;
+
+ public MessagingLinearLayout(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.MessagingLinearLayout, 0,
+ 0);
+
+ final int N = a.getIndexCount();
+ for (int i = 0; i < N; i++) {
+ int attr = a.getIndex(i);
+ switch (attr) {
+ case R.styleable.MessagingLinearLayout_maxHeight:
+ mMaxHeight = a.getDimensionPixelSize(i, 0);
+ break;
+ case R.styleable.MessagingLinearLayout_spacing:
+ mSpacing = a.getDimensionPixelSize(i, 0);
+ break;
+ }
+ }
+
+ if (mMaxHeight <= 0) {
+ throw new IllegalStateException(
+ "MessagingLinearLayout: Must specify positive maxHeight");
+ }
+
+ a.recycle();
+ }
+
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // This is essentially a bottom-up linear layout that only adds children that fit entirely
+ // up to a maximum height.
+
+ switch (MeasureSpec.getMode(heightMeasureSpec)) {
+ case MeasureSpec.AT_MOST:
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ Math.min(mMaxHeight, MeasureSpec.getSize(heightMeasureSpec)),
+ MeasureSpec.AT_MOST);
+ break;
+ case MeasureSpec.UNSPECIFIED:
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ mMaxHeight,
+ MeasureSpec.AT_MOST);
+ break;
+ case MeasureSpec.EXACTLY:
+ break;
+ }
+ final int targetHeight = MeasureSpec.getSize(heightMeasureSpec);
+ final int count = getChildCount();
+
+ for (int i = 0; i < count; ++i) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ lp.hide = true;
+ }
+
+ int totalHeight = mPaddingTop + mPaddingBottom;
+ boolean first = true;
+
+ // Starting from the bottom: we measure every view as if it were the only one. If it still
+ // fits, we take it, otherwise we stop there.
+ for (int i = count - 1; i >= 0 && totalHeight < targetHeight; i--) {
+ if (getChildAt(i).getVisibility() == GONE) {
+ continue;
+ }
+ final View child = getChildAt(i);
+ LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
+
+ if (child instanceof ImageFloatingTextView) {
+ // Pretend we need the image padding for all views, we don't know which
+ // one will end up needing to do this (might end up not using all the space,
+ // but calculating this exactly would be more expensive).
+ ((ImageFloatingTextView) child).setNumIndentLines(mIndentLines);
+ }
+
+ measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+
+ final int childHeight = child.getMeasuredHeight();
+ int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
+ lp.bottomMargin + (first ? 0 : mSpacing));
+ first = false;
+
+ if (newHeight <= targetHeight) {
+ totalHeight = newHeight;
+ lp.hide = false;
+ } else {
+ break;
+ }
+ }
+
+ // Now that we know which views to take, fix up the indents and see what width we get.
+ int measuredWidth = mPaddingLeft + mPaddingRight;
+ int imageLines = mIndentLines;
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+ if (child.getVisibility() == GONE || lp.hide) {
+ continue;
+ }
+
+ if (child instanceof ImageFloatingTextView) {
+ ImageFloatingTextView textChild = (ImageFloatingTextView) child;
+ if (imageLines == 2 && textChild.getLineCount() > 2) {
+ // HACK: If we need indent for two lines, and they're coming from the same
+ // view, we need extra spacing to compensate for the lack of margins,
+ // so add an extra line of indent.
+ imageLines = 3;
+ }
+ boolean changed = textChild.setNumIndentLines(Math.max(0, imageLines));
+ if (changed) {
+ measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+ }
+ imageLines -= textChild.getLineCount();
+ }
+
+ measuredWidth = Math.max(measuredWidth,
+ child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin
+ + mPaddingLeft + mPaddingRight);
+ }
+
+
+ setMeasuredDimension(
+ resolveSize(Math.max(getSuggestedMinimumWidth(), measuredWidth),
+ widthMeasureSpec),
+ resolveSize(Math.max(getSuggestedMinimumHeight(), totalHeight),
+ heightMeasureSpec));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ final int paddingLeft = mPaddingLeft;
+
+ int childTop;
+
+ // Where right end of child should go
+ final int width = right - left;
+ final int childRight = width - mPaddingRight;
+
+ final int layoutDirection = getLayoutDirection();
+ final int count = getChildCount();
+
+ childTop = mPaddingTop;
+
+ boolean first = true;
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+ if (child.getVisibility() == GONE || lp.hide) {
+ continue;
+ }
+
+ final int childWidth = child.getMeasuredWidth();
+ final int childHeight = child.getMeasuredHeight();
+
+ int childLeft;
+ if (layoutDirection == LAYOUT_DIRECTION_RTL) {
+ childLeft = childRight - childWidth - lp.rightMargin;
+ } else {
+ childLeft = paddingLeft + lp.leftMargin;
+ }
+
+ if (!first) {
+ childTop += mSpacing;
+ }
+
+ childTop += lp.topMargin;
+ child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
+
+ childTop += childHeight + lp.bottomMargin;
+
+ first = false;
+ }
+ }
+
+ @Override
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp.hide) {
+ return true;
+ }
+ return super.drawChild(canvas, child, drawingTime);
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return new LayoutParams(mContext, attrs);
+ }
+
+ @Override
+ protected LayoutParams generateDefaultLayoutParams() {
+ return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+
+ }
+
+ @Override
+ protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+ LayoutParams copy = new LayoutParams(lp.width, lp.height);
+ if (lp instanceof MarginLayoutParams) {
+ copy.copyMarginsFrom((MarginLayoutParams) lp);
+ }
+ return copy;
+ }
+
+ @RemotableViewMethod
+ /**
+ * Sets how many lines should be indented to avoid a floating image.
+ */
+ public void setNumIndentLines(int numberLines) {
+ mIndentLines = numberLines;
+ }
+
+ public static class LayoutParams extends MarginLayoutParams {
+
+ boolean hide = false;
+
+ public LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ }
+
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index c4347f8..8b9d503 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -17,9 +17,15 @@
package com.android.internal.widget;
+import com.android.internal.R;
+
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,7 +44,6 @@
import android.view.animation.AnimationUtils;
import android.widget.AbsListView;
import android.widget.OverScroller;
-import com.android.internal.R;
public class ResolverDrawerLayout extends ViewGroup {
private static final String TAG = "ResolverDrawerLayout";
@@ -86,6 +91,8 @@
private final OverScroller mScroller;
private final VelocityTracker mVelocityTracker;
+ private Drawable mScrollIndicatorDrawable;
+
private OnDismissedListener mOnDismissedListener;
private RunOnDismissedListener mRunOnDismissedListener;
@@ -127,6 +134,8 @@
mMaxCollapsedHeight);
a.recycle();
+ mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material);
+
mScroller = new OverScroller(context, AnimationUtils.loadInterpolator(context,
android.R.interpolator.decelerate_quint));
mVelocityTracker = VelocityTracker.obtain();
@@ -202,8 +211,7 @@
}
final boolean isCollapsedNew = mCollapseOffset != 0;
if (isCollapsedOld != isCollapsedNew) {
- notifyViewAccessibilityStateChangedIfNeeded(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ onCollapsedChanged(isCollapsedNew);
}
} else {
// Start out collapsed at first unless we restored state for otherwise
@@ -442,8 +450,7 @@
mTopOffset += dy;
final boolean isCollapsedNew = newPos != 0;
if (isCollapsedOld != isCollapsedNew) {
- notifyViewAccessibilityStateChangedIfNeeded(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ onCollapsedChanged(isCollapsedNew);
}
postInvalidateOnAnimation();
return dy;
@@ -451,6 +458,15 @@
return 0;
}
+ private void onCollapsedChanged(boolean isCollapsed) {
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+
+ if (mScrollIndicatorDrawable != null) {
+ setWillNotDraw(!isCollapsed);
+ }
+ }
+
void dispatchOnDismissed() {
if (mOnDismissedListener != null) {
mOnDismissedListener.onDismissed();
@@ -709,6 +725,15 @@
}
@Override
+ public void onDrawForeground(Canvas canvas) {
+ if (mScrollIndicatorDrawable != null) {
+ mScrollIndicatorDrawable.draw(canvas);
+ }
+
+ super.onDrawForeground(canvas);
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int sourceWidth = MeasureSpec.getSize(widthMeasureSpec);
int widthSize = sourceWidth;
@@ -794,6 +819,8 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = getWidth();
+ View indicatorHost = null;
+
int ypos = mTopOffset;
int leftEdge = getPaddingLeft();
int rightEdge = width - getPaddingRight();
@@ -802,6 +829,9 @@
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp.hasNestedScrollIndicator) {
+ indicatorHost = child;
+ }
if (child.getVisibility() == GONE) {
continue;
@@ -822,6 +852,20 @@
ypos = bottom + lp.bottomMargin;
}
+
+ if (mScrollIndicatorDrawable != null) {
+ if (indicatorHost != null) {
+ final int left = indicatorHost.getLeft();
+ final int right = indicatorHost.getRight();
+ final int bottom = indicatorHost.getTop();
+ final int top = bottom - mScrollIndicatorDrawable.getIntrinsicHeight();
+ mScrollIndicatorDrawable.setBounds(left, top, right, bottom);
+ setWillNotDraw(!isCollapsed());
+ } else {
+ mScrollIndicatorDrawable = null;
+ setWillNotDraw(true);
+ }
+ }
}
@Override
@@ -861,6 +905,7 @@
public static class LayoutParams extends MarginLayoutParams {
public boolean alwaysShow;
public boolean ignoreOffset;
+ public boolean hasNestedScrollIndicator;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
@@ -873,6 +918,9 @@
ignoreOffset = a.getBoolean(
R.styleable.ResolverDrawerLayout_LayoutParams_layout_ignoreOffset,
false);
+ hasNestedScrollIndicator = a.getBoolean(
+ R.styleable.ResolverDrawerLayout_LayoutParams_layout_hasNestedScrollIndicator,
+ false);
a.recycle();
}
@@ -884,6 +932,7 @@
super(source);
this.alwaysShow = source.alwaysShow;
this.ignoreOffset = source.ignoreOffset;
+ this.hasNestedScrollIndicator = source.hasNestedScrollIndicator;
}
public LayoutParams(MarginLayoutParams source) {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7ff38fd5..d3dca5d9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -592,6 +592,7 @@
char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
+ char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
@@ -701,6 +702,9 @@
if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
addOption("-Xjitsaveprofilinginfo");
}
+ parseRuntimeOption("dalvik.vm.jitprithreadweight",
+ jitprithreadweightOptBuf,
+ "-Xjitprithreadweight:");
property_get("ro.config.low_ram", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 6e9830e..dc9b656 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -36,7 +36,7 @@
// ----------------------------------------------------------------------------
-#define EGL_QCOM_PROTECTED_CONTENT 0x32E0
+#define EGL_PROTECTED_CONTENT_EXT 0x32C0
namespace android {
@@ -64,19 +64,12 @@
EGLDisplay dpy = eglGetCurrentDisplay();
EGLContext ctx = eglGetCurrentContext();
- if (dpy == EGL_NO_DISPLAY) {
- ALOGI("isProtectedSurface: invalid current EGLDisplay");
- return false;
- }
-
- if (ctx == EGL_NO_CONTEXT) {
- ALOGI("isProtectedSurface: invalid current EGLContext");
+ if (dpy == EGL_NO_DISPLAY || ctx == EGL_NO_CONTEXT) {
return false;
}
EGLint isProtected = EGL_FALSE;
- // TODO: Change the enum value below when an extension is ratified.
- eglQueryContext(dpy, ctx, EGL_QCOM_PROTECTED_CONTENT, &isProtected);
+ eglQueryContext(dpy, ctx, EGL_PROTECTED_CONTENT_EXT, &isProtected);
return isProtected;
}
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index e5c4a2d..0de6549 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -175,7 +175,7 @@
PathParser::ParseResult result;
PathData data;
- PathParser::getPathDataFromString(&data, &result, pathString, stringLength);
+ PathParser::getPathDataFromAsciiString(&data, &result, pathString, stringLength);
if (result.failureOccurred) {
doThrowIAE(env, result.failureMessage.c_str());
}
@@ -343,7 +343,7 @@
}
static const JNINativeMethod gMethods[] = {
- {"nCreateRenderer", "!(J)J", (void*)createTree},
+ {"nCreateTree", "!(J)J", (void*)createTree},
{"nSetRendererViewportSize", "!(JFF)V", (void*)setTreeViewportSize},
{"nSetRootAlpha", "!(JF)Z", (void*)setRootAlpha},
{"nGetRootAlpha", "!(J)F", (void*)getRootAlpha},
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index 90d69d2..5c961d9 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -370,10 +370,6 @@
retVal = 0;
break;
- case CONTEXT_HUB_LOAD_OS:
- retVal = 0;
- break;
-
default:
retVal = -1;
break;
diff --git a/core/jni/android_util_PathParser.cpp b/core/jni/android_util_PathParser.cpp
index 0c867f1..53669a8 100644
--- a/core/jni/android_util_PathParser.cpp
+++ b/core/jni/android_util_PathParser.cpp
@@ -34,7 +34,7 @@
SkPath* skPath = reinterpret_cast<SkPath*>(skPathHandle);
PathParser::ParseResult result;
- PathParser::parseStringForSkPath(skPath, &result, pathString, strLength);
+ PathParser::parseAsciiStringForSkPath(skPath, &result, pathString, strLength);
env->ReleaseStringUTFChars(inputPathStr, pathString);
if (result.failureOccurred) {
doThrowIAE(env, result.failureMessage.c_str());
@@ -56,7 +56,7 @@
const char* pathString = env->GetStringUTFChars(inputStr, NULL);
PathData* pathData = new PathData();
PathParser::ParseResult result;
- PathParser::getPathDataFromString(pathData, &result, pathString, strLength);
+ PathParser::getPathDataFromAsciiString(pathData, &result, pathString, strLength);
env->ReleaseStringUTFChars(inputStr, pathString);
if (!result.failureOccurred) {
return reinterpret_cast<jlong>(pathData);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 778f797..1ed93cc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3008,6 +3008,12 @@
<permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
android:protectionLevel="signature|setup" />
+ <!-- @SystemApi Allows an application to replace the app name displayed alongside notifications
+ in the N-release and later.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"
+ android:protectionLevel="signature|privileged" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
new file mode 100644
index 0000000..7d718e0
--- /dev/null
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -0,0 +1,80 @@
+<?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
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:tag="messaging"
+ >
+ <include layout="@layout/notification_template_header" />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="top"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:paddingStart="@dimen/notification_content_margin_start"
+ android:paddingEnd="@dimen/notification_content_margin_end"
+ android:minHeight="@dimen/notification_min_content_height"
+ android:clipToPadding="false"
+ android:orientation="vertical"
+ >
+ <include layout="@layout/notification_template_part_line1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/notification_messaging"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/notification_content_margin_bottom"
+ android:spacing="@dimen/notification_messaging_spacing"
+ android:maxHeight="212dp">
+ <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text0"
+ style="@style/Widget.Material.Notification.MessagingText"
+ />
+ <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text1"
+ style="@style/Widget.Material.Notification.MessagingText"
+ />
+ <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text2"
+ style="@style/Widget.Material.Notification.MessagingText"
+ />
+ <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text3"
+ style="@style/Widget.Material.Notification.MessagingText"
+ />
+ <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text4"
+ style="@style/Widget.Material.Notification.MessagingText"
+ />
+ <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text5"
+ style="@style/Widget.Material.Notification.MessagingText"
+ />
+ <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text6"
+ style="@style/Widget.Material.Notification.MessagingText"
+ />
+ </com.android.internal.widget.MessagingLinearLayout>
+ </LinearLayout>
+ <include layout="@layout/notification_material_action_list" />
+ </LinearLayout>
+ <include layout="@layout/notification_template_right_icon" />
+</FrameLayout>
diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml
index 15ccc67..b652127 100644
--- a/core/res/res/layout/notification_template_right_icon.xml
+++ b/core/res/res/layout/notification_template_right_icon.xml
@@ -16,9 +16,9 @@
-->
<ImageView android:id="@+id/right_icon" xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_marginEnd="16dp"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_width"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
android:layout_marginTop="36dp"
android:layout_gravity="top|end"
android:scaleType="centerCrop"
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 5850e50..ae94503 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -30,33 +30,37 @@
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
android:elevation="8dp"
- android:background="@color/white" >
- <TextView android:id="@+id/profile_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginEnd="8dp"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:visibility="gone"
- style="?attr/borderlessButtonStyle"
- android:textAppearance="?attr/textAppearanceButton"
- android:textColor="@color/material_deep_teal_500"
- android:gravity="center_vertical"
- android:layout_alignParentTop="true"
- android:layout_alignParentRight="true"
- android:singleLine="true"/>
- <TextView android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minHeight="56dp"
- android:textAppearance="?attr/textAppearanceMedium"
- android:gravity="start|center_vertical"
- android:paddingStart="?attr/dialogPreferredPadding"
- android:paddingEnd="?attr/dialogPreferredPadding"
- android:paddingTop="8dp"
- android:layout_below="@id/profile_button"
- android:layout_alignParentLeft="true"
- android:paddingBottom="8dp" />
+ android:background="@color/white">
+
+ <TextView
+ android:id="@+id/profile_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginEnd="8dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:visibility="gone"
+ style="?attr/borderlessButtonStyle"
+ android:textAppearance="?attr/textAppearanceButton"
+ android:textColor="@color/material_deep_teal_500"
+ android:gravity="center_vertical"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="56dp"
+ android:textAppearance="?attr/textAppearanceMedium"
+ android:gravity="start|center_vertical"
+ android:paddingStart="?attr/dialogPreferredPadding"
+ android:paddingEnd="?attr/dialogPreferredPadding"
+ android:paddingTop="8dp"
+ android:layout_below="@id/profile_button"
+ android:layout_alignParentLeft="true"
+ android:paddingBottom="8dp" />
</RelativeLayout>
<ListView
@@ -68,6 +72,7 @@
android:background="@color/white"
android:elevation="8dp"
android:nestedScrollingEnabled="true"
+ android:scrollIndicators="top|bottom"
android:divider="@null" />
<TextView android:id="@+id/empty"
@@ -84,11 +89,12 @@
<LinearLayout
android:id="@+id/button_bar"
android:visibility="gone"
- style="?android:attr/buttonBarStyle"
+ style="?attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_ignoreOffset="true"
android:layout_alwaysShow="true"
+ android:layout_hasNestedScrollIndicator="true"
android:gravity="end|center_vertical"
android:orientation="horizontal"
android:layoutDirection="locale"
@@ -99,26 +105,30 @@
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:elevation="8dp">
- <Button android:id="@+id/button_once"
- android:layout_width="wrap_content"
- android:layout_gravity="start"
- android:maxLines="2"
- style="?android:attr/buttonBarNegativeButtonStyle"
- android:minHeight="@dimen/alert_dialog_button_bar_height"
- android:layout_height="wrap_content"
- android:enabled="false"
- android:text="@string/activity_resolver_use_once"
- android:onClick="onButtonClick" />
- <Button android:id="@+id/button_always"
- android:layout_width="wrap_content"
- android:layout_gravity="end"
- android:maxLines="2"
- android:minHeight="@dimen/alert_dialog_button_bar_height"
- style="?android:attr/buttonBarPositiveButtonStyle"
- android:layout_height="wrap_content"
- android:enabled="false"
- android:text="@string/activity_resolver_use_always"
- android:onClick="onButtonClick" />
+
+ <Button
+ android:id="@+id/button_once"
+ android:layout_width="wrap_content"
+ android:layout_gravity="start"
+ android:maxLines="2"
+ style="?attr/buttonBarNegativeButtonStyle"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/activity_resolver_use_once"
+ android:onClick="onButtonClick" />
+
+ <Button
+ android:id="@+id/button_always"
+ android:layout_width="wrap_content"
+ android:layout_gravity="end"
+ android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ style="?attr/buttonBarPositiveButtonStyle"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/activity_resolver_use_always"
+ android:onClick="onButtonClick" />
</LinearLayout>
</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 31361e5..02dc2ed 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -22,8 +22,7 @@
android:layout_height="match_parent"
android:maxWidth="@dimen/resolver_max_width"
android:maxCollapsedHeight="144dp"
- android:id="@id/contentPanel"
- >
+ android:id="@id/contentPanel">
<LinearLayout
android:layout_width="match_parent"
@@ -31,66 +30,75 @@
android:layout_alwaysShow="true"
android:orientation="vertical"
android:background="@color/white"
- android:elevation="8dp" >
+ android:elevation="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="64dp"
- android:orientation="horizontal" >
+ android:orientation="horizontal">
- <ImageView android:id="@+id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="start|top"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
- android:layout_marginTop="20dp"
- android:scaleType="fitCenter" />
- <TextView android:id="@+id/title"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:layout_marginStart="16dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:gravity="start|center_vertical"
- android:paddingEnd="16dp" />
- <LinearLayout android:id="@+id/profile_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginTop="4dp"
- android:layout_marginEnd="4dp"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
- android:focusable="true"
- android:visibility="gone"
- style="?attr/borderlessButtonStyle">
- <ImageView android:id="@+id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="start|center_vertical"
- android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
- android:scaleType="fitCenter" />
- <TextView android:id="@id/text1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start|center_vertical"
- android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
- android:textAppearance="?attr/textAppearanceButton"
- android:textColor="?attr/textColorPrimary"
- android:minLines="1"
- android:maxLines="1"
- android:ellipsize="marquee" />
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="start|top"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginTop="20dp"
+ android:scaleType="fitCenter" />
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="?attr/listPreferredItemHeight"
+ android:layout_marginStart="16dp"
+ android:textAppearance="?attr/textAppearanceMedium"
+ android:gravity="start|center_vertical"
+ android:paddingEnd="16dp" />
+
+ <LinearLayout
+ android:id="@+id/profile_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginTop="4dp"
+ android:layout_marginEnd="4dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:focusable="true"
+ android:visibility="gone"
+ style="?attr/borderlessButtonStyle">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="start|center_vertical"
+ android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"
+ android:scaleType="fitCenter" />
+
+ <TextView
+ android:id="@id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|center_vertical"
+ android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
+ android:textAppearance="?attr/textAppearanceButton"
+ android:textColor="?attr/textColorPrimary"
+ android:minLines="1"
+ android:maxLines="1"
+ android:ellipsize="marquee" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/button_bar"
android:visibility="gone"
- style="?android:attr/buttonBarStyle"
+ style="?attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
@@ -104,30 +112,36 @@
android:paddingEnd="12dp"
android:background="@color/white"
android:elevation="8dp">
- <Button android:id="@+id/button_once"
- android:layout_width="wrap_content"
- android:layout_gravity="start"
- android:maxLines="2"
- style="?android:attr/buttonBarNegativeButtonStyle"
- android:minHeight="@dimen/alert_dialog_button_bar_height"
- android:layout_height="wrap_content"
- android:enabled="false"
- android:text="@string/activity_resolver_use_once"
- android:onClick="onButtonClick" />
- <Button android:id="@+id/button_always"
- android:layout_width="wrap_content"
- android:layout_gravity="end"
- android:maxLines="2"
- android:minHeight="@dimen/alert_dialog_button_bar_height"
- style="?android:attr/buttonBarPositiveButtonStyle"
- android:layout_height="wrap_content"
- android:enabled="false"
- android:text="@string/activity_resolver_use_always"
- android:onClick="onButtonClick" />
+
+ <Button
+ android:id="@+id/button_once"
+ android:layout_width="wrap_content"
+ android:layout_gravity="start"
+ android:maxLines="2"
+ style="?attr/buttonBarNegativeButtonStyle"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/activity_resolver_use_once"
+ android:onClick="onButtonClick" />
+
+ <Button
+ android:id="@+id/button_always"
+ android:layout_width="wrap_content"
+ android:layout_gravity="end"
+ android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ style="?attr/buttonBarPositiveButtonStyle"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/activity_resolver_use_always"
+ android:onClick="onButtonClick" />
</LinearLayout>
- <View android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/dividerVertical" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/dividerVertical" />
</LinearLayout>
<ListView
@@ -139,7 +153,6 @@
android:background="@color/white"
android:elevation="8dp"
android:nestedScrollingEnabled="true"
- android:divider="@null"
- />
+ android:divider="@null" />
</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0ed1f13..85e0b88 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8129,10 +8129,16 @@
<attr name="maxCollapsedHeightSmall" format="dimension" />
</declare-styleable>
+ <declare-styleable name="MessagingLinearLayout">
+ <attr name="maxHeight" />
+ <attr name="spacing" />
+ </declare-styleable>
+
<declare-styleable name="ResolverDrawerLayout_LayoutParams">
<attr name="layout_alwaysShow" format="boolean" />
<attr name="layout_ignoreOffset" format="boolean" />
<attr name="layout_gravity" />
+ <attr name="layout_hasNestedScrollIndicator" format="boolean" />
</declare-styleable>
<!-- @hide -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index dd54d57..9178305 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -162,9 +162,9 @@
<dimen name="notification_min_height">92dp</dimen>
<!-- The width of the big icons in notifications. -->
- <dimen name="notification_large_icon_width">64dp</dimen>
+ <dimen name="notification_large_icon_width">40dp</dimen>
<!-- The width of the big icons in notifications. -->
- <dimen name="notification_large_icon_height">64dp</dimen>
+ <dimen name="notification_large_icon_height">40dp</dimen>
<!-- The minimum width of the app name in the header if it shrinks -->
<dimen name="notification_header_shrink_min_width">72dp</dimen>
@@ -181,6 +181,9 @@
<!-- The margin of the content to an image-->
<dimen name="notification_content_image_margin_end">8dp</dimen>
+ <!-- The spacing between messages in Notification.MessagingStyle -->
+ <dimen name="notification_messaging_spacing">6dp</dimen>
+
<!-- Preferred width of the search view. -->
<dimen name="search_view_preferred_width">320dip</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 96731cf..0a99239 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -349,18 +349,18 @@
<!-- SSL CA cert notification --> <skip />
<!-- Shows up when there is a user SSL CA Cert installed on the
device. Indicates to the user that SSL traffic can be intercepted. [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_warning">Network may be monitored</string>
- <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
- i.e. "Network may be monitored". This says that an unknown party is doing the monitoring.
- [CHAR LIMIT=100]-->
+ <plurals name="ssl_ca_cert_warning">
+ <item quantity="one">Certificate authority installed</item>
+ <item quantity="other">Certificate authorities installed</item>
+ </plurals>
+ <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning".
+ This says that an unknown party is doing the monitoring. [CHAR LIMIT=100]-->
<string name="ssl_ca_cert_noti_by_unknown">By an unknown third party</string>
- <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
- i.e. "Network may be monitored". This indicates that an unspecified administrator is doing
- the monitoring. [CHAR LIMIT=100]-->
+ <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning".
+ This indicates that an unspecified administrator is doing the monitoring. [CHAR LIMIT=100]-->
<string name="ssl_ca_cert_noti_by_administrator">By your work profile administrator</string>
- <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
- i.e. "Network may be monitored". This indicates who is doing the monitoring.
- [CHAR LIMIT=100]-->
+ <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning".
+ This indicates who is doing the monitoring. [CHAR LIMIT=100]-->
<string name="ssl_ca_cert_noti_managed">By <xliff:g id="managing_domain">%s</xliff:g></string>
<!-- Work profile deleted notification--> <skip />
@@ -2552,21 +2552,29 @@
<!-- Title of intent resolver dialog when selecting an application to run
and a previously used application is known. -->
<string name="whichApplicationNamed">Complete action using %1$s</string>
+ <!-- Generic label for a link to a intent resolver. -->
+ <string name="whichApplicationLabel">Complete action</string>
<!-- Title of intent resolver dialog when selecting a viewer application to run. -->
<string name="whichViewApplication">Open with</string>
<!-- Title of intent resolver dialog when selecting a viewer application to run
and a previously used application is known. -->
<string name="whichViewApplicationNamed">Open with %1$s</string>
+ <!-- Label for a link to a intent resolver dialog to view something -->
+ <string name="whichViewApplicationLabel">Open</string>
<!-- Title of intent resolver dialog when selecting an editor application to run. -->
<string name="whichEditApplication">Edit with</string>
<!-- Title of intent resolver dialog when selecting an editor application to run
and a previously used application is known. -->
<string name="whichEditApplicationNamed">Edit with %1$s</string>
+ <!-- Label for a link to a intent resolver dialog when selecting an editor application -->
+ <string name="whichEditApplicationLabel">Edit</string>
<!-- Title of intent resolver dialog when selecting a sharing application to run. -->
<string name="whichSendApplication">Share with</string>
<!-- Title of intent resolver dialog when selecting a sharing application to run
and a previously used application is known. -->
<string name="whichSendApplicationNamed">Share with %1$s</string>
+ <!-- Label for a link to a intent resolver dialog to sharing something -->
+ <string name="whichSendApplicationLabel">Share</string>
<!-- Title of intent resolver dialog when selecting an application to run to
send content to a specific recipient. Often used for email. -->
<string name="whichSendToApplication">Send using</string>
@@ -2574,11 +2582,23 @@
send content to a specific recipient and a previously used application is known.
Often used for email. -->
<string name="whichSendToApplicationNamed">Send using %1$s</string>
+ <!-- Label for a link to a intent resolver dialog to send content to a specific recipient. -->
+ <string name="whichSendToApplicationLabel">Send</string>
<!-- Title of intent resolver dialog when selecting a HOME application to run. -->
<string name="whichHomeApplication">Select a Home app</string>
<!-- Title of intent resolver dialog when selecting a HOME application to run
and a previously used application is known. -->
<string name="whichHomeApplicationNamed">Use %1$s as Home</string>
+ <!-- Label for a link to a intent resolver dialog when selecting a HOME -->
+ <string name="whichHomeApplicationLabel">Capture image</string>
+ <!-- Option to always use the selected application resolution in the future. See the "Complete action using" dialog title-->
+ <!-- Title of intent resolver dialog when capturing an image. -->
+ <string name="whichImageCaptureApplication">Capture image with</string>
+ <!-- Title of intent resolver dialog when capturing an image
+ and a previously used application is known. -->
+ <string name="whichImageCaptureApplicationNamed">Capture image with %1$s</string>
+ <!-- Label for a link to a intent resolver dialog when capturing an image -->
+ <string name="whichImageCaptureApplicationLabel">Capture image</string>
<!-- Option to always use the selected application resolution in the future. See the "Complete action using" dialog title-->
<string name="alwaysUse">Use by default for this action.</string>
<!-- Title of the list of alternate options to complete an action shown when the
@@ -4028,6 +4048,9 @@
<!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
<string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
+ <!-- [CHAR_LIMIT=NONE] Data saver: Feature description -->
+ <string name="data_saver_description">To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.</string>
+
<!-- Zen mode condition - summary: time duration in minutes. [CHAR LIMIT=NONE] -->
<plurals name="zen_mode_duration_minutes_summary">
<item quantity="one">For one minute (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 2420c1a..8a33406 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -456,6 +456,14 @@
<style name="Widget.Material.Notification.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal" />
+ <style name="Widget.Material.Notification.MessagingText" parent="Widget.Material.Light.TextView">
+ <item name="layout_width">match_parent</item>
+ <item name="layout_height">wrap_content</item>
+ <item name="ellipsize">end</item>
+ <item name="visibility">gone</item>
+ <item name="textAppearance">@style/TextAppearance.Material.Notification</item>
+ </style>
+
<!-- Widget Styles -->
<style name="Material"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7eaff7b..541ee75 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1095,7 +1095,6 @@
<java-symbol type="string" name="ssl_ca_cert_noti_by_unknown" />
<java-symbol type="string" name="ssl_ca_cert_noti_by_administrator" />
<java-symbol type="string" name="ssl_ca_cert_noti_managed" />
- <java-symbol type="string" name="ssl_ca_cert_warning" />
<java-symbol type="string" name="work_profile_deleted" />
<java-symbol type="string" name="work_profile_deleted_description" />
<java-symbol type="string" name="work_profile_deleted_details" />
@@ -1115,6 +1114,7 @@
<java-symbol type="plurals" name="matches_found" />
<java-symbol type="plurals" name="restr_pin_countdown" />
<java-symbol type="plurals" name="pinpuk_attempts" />
+ <java-symbol type="plurals" name="ssl_ca_cert_warning" />
<java-symbol type="array" name="carrier_properties" />
<java-symbol type="array" name="config_sms_enabled_locking_shift_tables" />
@@ -1386,7 +1386,6 @@
<java-symbol type="xml" name="password_kbd_qwerty" />
<java-symbol type="xml" name="autotext" />
- <java-symbol type="xml" name="eri" />
<java-symbol type="xml" name="password_kbd_numeric" />
<java-symbol type="xml" name="password_kbd_qwerty_shifted" />
<java-symbol type="xml" name="password_kbd_symbols" />
@@ -2103,6 +2102,7 @@
<java-symbol type="dimen" name="timepicker_text_size_normal" />
<java-symbol type="dimen" name="timepicker_text_size_inner" />
<java-symbol type="string" name="battery_saver_description" />
+ <java-symbol type="string" name="data_saver_description" />
<java-symbol type="string" name="zen_mode_forever" />
<java-symbol type="string" name="zen_mode_forever_dnd" />
<java-symbol type="string" name="zen_mode_rule_name_combination" />
@@ -2199,14 +2199,22 @@
<java-symbol type="attr" name="touchscreenBlocksFocus" />
<java-symbol type="layout" name="resolver_list_with_default" />
<java-symbol type="string" name="whichApplicationNamed" />
+ <java-symbol type="string" name="whichApplicationLabel" />
<java-symbol type="string" name="whichViewApplication" />
<java-symbol type="string" name="whichViewApplicationNamed" />
+ <java-symbol type="string" name="whichViewApplicationLabel" />
<java-symbol type="string" name="whichEditApplication" />
<java-symbol type="string" name="whichEditApplicationNamed" />
+ <java-symbol type="string" name="whichEditApplicationLabel" />
<java-symbol type="string" name="whichSendApplication" />
<java-symbol type="string" name="whichSendApplicationNamed" />
+ <java-symbol type="string" name="whichSendApplicationLabel" />
<java-symbol type="string" name="whichSendToApplication" />
<java-symbol type="string" name="whichSendToApplicationNamed" />
+ <java-symbol type="string" name="whichSendToApplicationLabel" />
+ <java-symbol type="string" name="whichImageCaptureApplication" />
+ <java-symbol type="string" name="whichImageCaptureApplicationNamed" />
+ <java-symbol type="string" name="whichImageCaptureApplicationLabel" />
<java-symbol type="attr" name="lightY" />
<java-symbol type="attr" name="lightZ" />
<java-symbol type="attr" name="lightRadius" />
@@ -2236,6 +2244,7 @@
<java-symbol type="array" name="networks_not_clear_data" />
<java-symbol type="bool" name="config_switch_phone_on_voice_reg_state_change" />
<java-symbol type="string" name="whichHomeApplicationNamed" />
+ <java-symbol type="string" name="whichHomeApplicationLabel" />
<java-symbol type="bool" name="config_sms_force_7bit_encoding" />
<java-symbol type="bool" name="config_defaultWindowFeatureOptionsPanel" />
<java-symbol type="bool" name="config_defaultWindowFeatureContextMenu" />
@@ -2494,6 +2503,8 @@
<java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
<java-symbol type="layout" name="app_anr_dialog" />
+ <java-symbol type="layout" name="notification_template_material_messaging" />
+
<java-symbol type="id" name="aerr_wait" />
<java-symbol type="id" name="notification_content_container" />
@@ -2523,12 +2534,16 @@
<java-symbol type="string" name="carrier_app_notification_text" />
<java-symbol type="string" name="negative_duration" />
+ <java-symbol type="dimen" name="notification_messaging_spacing" />
+
<!-- WallpaperManager config -->
<java-symbol type="string" name="config_wallpaperCropperPackage" />
<java-symbol type="id" name="textSpacerNoTitle" />
<java-symbol type="id" name="titleDividerNoCustom" />
+ <java-symbol type="id" name="notification_messaging" />
+
<java-symbol type="bool" name="config_sustainedPerformanceModeSupported" />
<!-- Wearable input extract edit view -->
diff --git a/core/res/res/xml/eri.xml b/core/res/res/xml/eri.xml
deleted file mode 100644
index cd66f14..0000000
--- a/core/res/res/xml/eri.xml
+++ /dev/null
@@ -1,118 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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.
-*/
--->
-
-<!-- Note that IconMode can be only 0, ON or 1, FLASHING
- The icon is turned OFF if then IconIndex = 1 -->
-
-<EriFile VersionNumber="1357"
- NumberOfEriEntries="12"
- EriFileType="1">
-
- <CallPromptId Id="0"
- CallPromptText="CallPromptId0"/>
-
- <CallPromptId Id="1"
- CallPromptText="CallPromptId1"/>
-
- <CallPromptId Id="2"
- CallPromptText="CallPromptId2"/>
-
- <EriInfo RoamingIndicator="64"
- IconIndex="1"
- IconMode="0"
- EriText="T-CDMA 64"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="65"
- IconIndex="65"
- IconMode="0"
- EriText="T-CDMA 65"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="66"
- IconIndex="1"
- IconMode="0"
- EriText="T-CDMA Ext 66"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="67"
- IconIndex="67"
- IconMode="0"
- EriText="T-CDMA Ext 67"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="68"
- IconIndex="68"
- IconMode="0"
- EriText="T-CDMA Roam 68"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="69"
- IconIndex="69"
- IconMode="1"
- EriText="T-CDMA Ext 69"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="70"
- IconIndex="70"
- IconMode="1"
- EriText="T-CDMA Roam 70"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="71"
- IconIndex="1"
- IconMode="0"
- EriText="T-CDMA Ext 71"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="72"
- IconIndex="72"
- IconMode="0"
- EriText="T-CDMA Ext 72"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="73"
- IconIndex="73"
- IconMode="0"
- EriText="T-CDMA Roam 73"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="74"
- IconIndex="74"
- IconMode="1"
- EriText="T-CDMA Ext 74"
- CallPromptId="0"
- AlertId="0"/>
-
- <EriInfo RoamingIndicator="75"
- IconIndex="75"
- IconMode="1"
- EriText="T-CDMA Roam 75"
- CallPromptId="0"
- AlertId="0"/>
-
-</EriFile>
diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
new file mode 100644
index 0000000..fd57baa
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.app.procstats;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.mockito.Mockito;
+
+/**
+ * Provides test cases for SparseMappingTable.
+ */
+public class SparseMappingTableTest extends TestCase {
+ private static final String TAG = "SparseMappingTableTest";
+
+ final byte ID1 = 1;
+ final byte ID2 = 2;
+
+ final long VALUE1 = 100;
+ final long VALUE2 = 10000000000L;
+
+ /**
+ * Test the parceling and unparceling logic when there is no data.
+ */
+ @SmallTest
+ public void testParcelingEmpty() throws Exception {
+ final SparseMappingTable data = new SparseMappingTable();
+ final SparseMappingTable.Table table = new SparseMappingTable.Table(data);
+
+ final Parcel dataParcel = Parcel.obtain();
+ data.writeToParcel(dataParcel);
+
+ final Parcel tableParcel = Parcel.obtain();
+ table.writeToParcel(tableParcel);
+
+ dataParcel.setDataPosition(0);
+ final SparseMappingTable data1 = new SparseMappingTable();
+ data1.readFromParcel(dataParcel);
+ Assert.assertEquals(0, dataParcel.dataAvail());
+ dataParcel.recycle();
+
+ tableParcel.setDataPosition(0);
+ final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1);
+ table1.readFromParcel(tableParcel);
+ Assert.assertEquals(0, tableParcel.dataAvail());
+ tableParcel.recycle();
+ }
+
+ /**
+ * Test the parceling and unparceling logic.
+ */
+ @SmallTest
+ public void testParceling() throws Exception {
+ int key;
+ final SparseMappingTable data = new SparseMappingTable();
+ final SparseMappingTable.Table table = new SparseMappingTable.Table(data);
+
+ key = table.getOrAddKey(ID1, 1);
+ table.setValue(key, VALUE1);
+
+ key = table.getOrAddKey(ID2, 1);
+ table.setValue(key, VALUE2);
+
+ final Parcel dataParcel = Parcel.obtain();
+ data.writeToParcel(dataParcel);
+
+ final Parcel tableParcel = Parcel.obtain();
+ table.writeToParcel(tableParcel);
+
+ dataParcel.setDataPosition(0);
+ final SparseMappingTable data1 = new SparseMappingTable();
+ data1.readFromParcel(dataParcel);
+ Assert.assertEquals(0, dataParcel.dataAvail());
+ dataParcel.recycle();
+
+ tableParcel.setDataPosition(0);
+ final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1);
+ table1.readFromParcel(tableParcel);
+ Assert.assertEquals(0, tableParcel.dataAvail());
+ tableParcel.recycle();
+
+ key = table1.getKey(ID1);
+ Assert.assertEquals(VALUE1, table1.getValue(key));
+
+ key = table1.getKey(ID2);
+ Assert.assertEquals(VALUE2, table1.getValue(key));
+ }
+
+
+ /**
+ * Test that after resetting you can still read data, you just get no values.
+ */
+ @SmallTest
+ public void testParcelingWithReset() throws Exception {
+ int key;
+ final SparseMappingTable data = new SparseMappingTable();
+ final SparseMappingTable.Table table = new SparseMappingTable.Table(data);
+
+ key = table.getOrAddKey(ID1, 1);
+ table.setValue(key, VALUE1);
+
+ data.reset();
+ table.resetTable();
+
+ key = table.getOrAddKey(ID2, 1);
+ table.setValue(key, VALUE2);
+
+ Log.d(TAG, "before: " + data.dumpInternalState(true));
+ Log.d(TAG, "before: " + table.dumpInternalState());
+
+ final Parcel dataParcel = Parcel.obtain();
+ data.writeToParcel(dataParcel);
+
+ final Parcel tableParcel = Parcel.obtain();
+ table.writeToParcel(tableParcel);
+
+ dataParcel.setDataPosition(0);
+ final SparseMappingTable data1 = new SparseMappingTable();
+ data1.readFromParcel(dataParcel);
+ Assert.assertEquals(0, dataParcel.dataAvail());
+ dataParcel.recycle();
+
+ tableParcel.setDataPosition(0);
+ final SparseMappingTable.Table table1 = new SparseMappingTable.Table(data1);
+ table1.readFromParcel(tableParcel);
+ Assert.assertEquals(0, tableParcel.dataAvail());
+ tableParcel.recycle();
+
+ key = table1.getKey(ID1);
+ Assert.assertEquals(SparseMappingTable.INVALID_KEY, key);
+
+ key = table1.getKey(ID2);
+ Assert.assertEquals(VALUE2, table1.getValue(key));
+
+ Log.d(TAG, " after: " + data1.dumpInternalState(true));
+ Log.d(TAG, " after: " + table1.dumpInternalState());
+ }
+
+ /**
+ * Test that it fails if you reset the data and not the table.
+ *
+ * Resetting the table and not the data is basically okay. The data in the
+ * SparseMappingTable will be leaked.
+ */
+ @SmallTest
+ public void testResetDataOnlyFails() throws Exception {
+ int key;
+ final SparseMappingTable data = new SparseMappingTable();
+ final SparseMappingTable.Table table = new SparseMappingTable.Table(data);
+
+ key = table.getOrAddKey(ID1, 1);
+ table.setValue(key, VALUE1);
+
+ Assert.assertEquals(VALUE1, table.getValue(key));
+
+ data.reset();
+
+ try {
+ table.getValue(key);
+ throw new Exception("Exception not thrown after mismatched reset calls.");
+ } catch (RuntimeException ex) {
+ // Good
+ }
+ }
+
+ /**
+ * Test that trying to get data that you didn't add fails correctly.
+ */
+ @SmallTest
+ public void testInvalidKey() throws Exception {
+ int key;
+ final SparseMappingTable data = new SparseMappingTable();
+ final SparseMappingTable.Table table = new SparseMappingTable.Table(data);
+
+ key = table.getKey(ID1);
+
+ // The key should be INVALID_KEY
+ Assert.assertEquals(SparseMappingTable.INVALID_KEY, key);
+
+ // If you get the value with getValueForId you get 0.
+ Assert.assertEquals(0, table.getValueForId(ID1));
+ }
+}
+
+
+
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index d412d7c..8a7d39b 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -111,6 +111,20 @@
<group gid="media" />
</permission>
+ <!-- These are permissions that were mapped to gids but we need
+ to keep them here until an upgrade from L to the current
+ version is to be supported. These permissions are built-in
+ and in L were not stored in packages.xml as a result if they
+ are not defined here while parsing packages.xml we would
+ ignore these permissions being granted to apps and not
+ propagate the granted state. From N we are storing the
+ built-in permissions in packages.xml as the saved storage
+ is negligible (one tag with the permission) compared to
+ the fragility as one can remove a built-in permission which
+ no longer needs to be mapped to gids and break grant propagation. -->
+ <permission name="android.permission.READ_EXTERNAL_STORAGE" />
+ <permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
diff --git a/docs/html/guide/topics/manifest/application-element.jd b/docs/html/guide/topics/manifest/application-element.jd
index 5600b5c..887b4ea 100644
--- a/docs/html/guide/topics/manifest/application-element.jd
+++ b/docs/html/guide/topics/manifest/application-element.jd
@@ -472,6 +472,8 @@
{@link android.os.StrictMode.VmPolicy.Builder#detectCleartextNetwork() StrictMode.VmPolicy.Builder.detectCleartextNetwork()}.
<p>This attribute was added in API level 23.</p>
+
+<p>This flag is ignored on Android N and above if an Android Network Security Config is present.</p>
</dd>
<dt><a name="vmSafeMode"></a>{@code android:vmSafeMode}</dt>
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index 832b9c3..98082ca 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -16,8 +16,18 @@
package android.graphics;
-public class PixelFormat
-{
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class PixelFormat {
+
+ /** @hide */
+ @IntDef({UNKNOWN, TRANSLUCENT, TRANSPARENT, OPAQUE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Opacity {}
+
/* these constants need to match those in hardware/hardware.h */
public static final int UNKNOWN = 0;
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index f15aff7..2886f0d 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -19,6 +19,7 @@
import android.content.res.AssetManager;
import android.util.Log;
import android.util.LongSparseArray;
+import android.util.LruCache;
import android.util.SparseArray;
import org.xmlpull.v1.XmlPullParserException;
@@ -63,6 +64,11 @@
private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache =
new LongSparseArray<SparseArray<Typeface>>(3);
+ /**
+ * Cache for Typeface objects dynamically loaded from assets. Currently max size is 16.
+ */
+ private static final LruCache<String, Typeface> sDynamicTypefaceCache = new LruCache<>(16);
+
static Typeface sDefaultTypeface;
static Map<String, Typeface> sSystemFontMap;
static FontFamily[] sFallbackFonts;
@@ -176,22 +182,50 @@
/**
* Create a new typeface from the specified font data.
- * @param mgr The application's asset manager
- * @param path The file name of the font data in the assets directory
+ *
+ * @param mgr The application's asset manager
+ * @param path The file name of the font data in the assets directory
* @return The new typeface.
*/
public static Typeface createFromAsset(AssetManager mgr, String path) {
if (sFallbackFonts != null) {
- FontFamily fontFamily = new FontFamily();
- if (fontFamily.addFontFromAsset(mgr, path)) {
- FontFamily[] families = { fontFamily };
- return createFromFamiliesWithDefault(families);
+ synchronized (sDynamicTypefaceCache) {
+ final String key = createAssetUid(mgr, path);
+ Typeface typeface = sDynamicTypefaceCache.get(key);
+ if (typeface != null) return typeface;
+
+ FontFamily fontFamily = new FontFamily();
+ if (fontFamily.addFontFromAsset(mgr, path)) {
+ FontFamily[] families = { fontFamily };
+ typeface = createFromFamiliesWithDefault(families);
+ sDynamicTypefaceCache.put(key, typeface);
+ return typeface;
+ }
}
}
throw new RuntimeException("Font asset not found " + path);
}
/**
+ * Creates a unique id for a given AssetManager and asset path.
+ *
+ * @param mgr AssetManager instance
+ * @param path The path for the asset.
+ * @return Unique id for a given AssetManager and asset path.
+ */
+ private static String createAssetUid(final AssetManager mgr, String path) {
+ final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers();
+ final StringBuilder builder = new StringBuilder();
+ final int size = pkgs.size();
+ for (int i = 0; i < size; i++) {
+ builder.append(pkgs.valueAt(i));
+ builder.append("-");
+ }
+ builder.append(path);
+ return builder.toString();
+ }
+
+ /**
* Create a new typeface from the specified font file.
*
* @param path The path to the font data.
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 4f600b4..cf5c563 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -16,7 +16,14 @@
package android.graphics.drawable;
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.AttrRes;
import android.annotation.ColorInt;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ActivityInfo.Config;
@@ -47,17 +54,12 @@
import android.util.Xml;
import android.view.View;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collection;
-import com.android.internal.R;
-
/**
* A Drawable is a general abstraction for "something that can be drawn." Most
* often you will deal with Drawable as the type of resource retrieved for
@@ -148,7 +150,7 @@
*
* @param canvas The canvas to draw into
*/
- public abstract void draw(Canvas canvas);
+ public abstract void draw(@NonNull Canvas canvas);
/**
* Specify a bounding rectangle for the Drawable. This is where the drawable
@@ -176,7 +178,7 @@
* Specify a bounding rectangle for the Drawable. This is where the drawable
* will draw when its draw() method is called.
*/
- public void setBounds(Rect bounds) {
+ public void setBounds(@NonNull Rect bounds) {
setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
}
@@ -188,7 +190,7 @@
* @param bounds Rect to receive the drawable's bounds (allocated by the
* caller).
*/
- public final void copyBounds(Rect bounds) {
+ public final void copyBounds(@NonNull Rect bounds) {
bounds.set(mBounds);
}
@@ -200,6 +202,7 @@
*
* @return A copy of the drawable's bounds
*/
+ @NonNull
public final Rect copyBounds() {
return new Rect(mBounds);
}
@@ -219,6 +222,7 @@
* @see #copyBounds()
* @see #copyBounds(android.graphics.Rect)
*/
+ @NonNull
public final Rect getBounds() {
if (mBounds == ZERO_BOUNDS_RECT) {
mBounds = new Rect();
@@ -237,6 +241,7 @@
*
* @return The dirty bounds of this drawable
*/
+ @NonNull
public Rect getDirtyBounds() {
return getBounds();
}
@@ -354,8 +359,8 @@
*
* @see #getCallback()
*/
- public final void setCallback(Callback cb) {
- mCallback = new WeakReference<Callback>(cb);
+ public final void setCallback(@Nullable Callback cb) {
+ mCallback = cb != null ? new WeakReference<>(cb) : null;
}
/**
@@ -366,11 +371,9 @@
*
* @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
+ @Nullable
public Callback getCallback() {
- if (mCallback != null) {
- return mCallback.get();
- }
- return null;
+ return mCallback != null ? mCallback.get() : null;
}
/**
@@ -399,7 +402,7 @@
*
* @see Callback#scheduleDrawable
*/
- public void scheduleSelf(Runnable what, long when) {
+ public void scheduleSelf(@NonNull Runnable what, long when) {
final Callback callback = getCallback();
if (callback != null) {
callback.scheduleDrawable(this, what, when);
@@ -415,7 +418,7 @@
*
* @see Callback#unscheduleDrawable
*/
- public void unscheduleSelf(Runnable what) {
+ public void unscheduleSelf(@NonNull Runnable what) {
final Callback callback = getCallback();
if (callback != null) {
callback.unscheduleDrawable(this, what);
@@ -429,7 +432,7 @@
* {@link android.view.View#LAYOUT_DIRECTION_RTL}
* @see #setLayoutDirection(int)
*/
- public int getLayoutDirection() {
+ public @View.ResolvedLayoutDir int getLayoutDirection() {
return mLayoutDirection;
}
@@ -441,6 +444,9 @@
* @param layoutDirection the resolved layout direction for the drawable,
* either {@link android.view.View#LAYOUT_DIRECTION_LTR}
* or {@link android.view.View#LAYOUT_DIRECTION_RTL}
+ * @return {@code true} if the layout direction change has caused the
+ * appearance of the drawable to change such that it needs to be
+ * re-drawn, {@code false} otherwise
* @see #getLayoutDirection()
*/
public final boolean setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) {
@@ -455,8 +461,9 @@
* Called when the drawable's resolved layout direction changes.
*
* @param layoutDirection the new resolved layout direction
- * @return true if the layout direction change has caused the appearance of
- * the drawable to change and it needs to be re-drawn
+ * @return {@code true} if the layout direction change has caused the
+ * appearance of the drawable to change such that it needs to be
+ * re-drawn, {@code false} otherwise
* @see #setLayoutDirection(int)
*/
public boolean onLayoutDirectionChanged(@View.ResolvedLayoutDir int layoutDirection) {
@@ -467,7 +474,7 @@
* Specify an alpha value for the drawable. 0 means fully transparent, and
* 255 means fully opaque.
*/
- public abstract void setAlpha(int alpha);
+ public abstract void setAlpha(@IntRange(from=0,to=255) int alpha);
/**
* Gets the current alpha value for the drawable. 0 means fully transparent,
@@ -476,6 +483,7 @@
* The default return value is 255 if the class does not override this method to return a value
* specific to its use of alpha.
*/
+ @IntRange(from=0,to=255)
public int getAlpha() {
return 0xFF;
}
@@ -489,7 +497,7 @@
* Drawables draw is private implementation detail, and not something apps
* should rely upon.
*/
- public void setXfermode(Xfermode mode) {
+ public void setXfermode(@Nullable Xfermode mode) {
// Base implementation drops it on the floor for compatibility. Whee!
}
@@ -592,7 +600,7 @@
*
* @return the current color filter, or {@code null} if none set
*/
- public ColorFilter getColorFilter() {
+ public @Nullable ColorFilter getColorFilter() {
return null;
}
@@ -629,7 +637,7 @@
* @param outRect the rect to populate with the hotspot bounds
* @see #setHotspotBounds(int, int, int, int)
*/
- public void getHotspotBounds(Rect outRect) {
+ public void getHotspotBounds(@NonNull Rect outRect) {
outRect.set(getBounds());
}
@@ -677,7 +685,7 @@
* of the Drawable to change (hence requiring an invalidate), otherwise
* returns false.
*/
- public boolean setState(final int[] stateSet) {
+ public boolean setState(@NonNull final int[] stateSet) {
if (!Arrays.equals(mStateSet, stateSet)) {
mStateSet = stateSet;
return onStateChange(stateSet);
@@ -692,7 +700,7 @@
* Some drawables may modify their imagery based on the selected state.
* @return An array of resource Ids describing the current state.
*/
- public int[] getState() {
+ public @NonNull int[] getState() {
return mStateSet;
}
@@ -709,7 +717,7 @@
* {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable
* currently in use.
*/
- public Drawable getCurrent() {
+ public @NonNull Drawable getCurrent() {
return this;
}
@@ -729,7 +737,7 @@
* of the Drawable to change (hence requiring an invalidate), otherwise
* returns false.
*/
- public final boolean setLevel(int level) {
+ public final boolean setLevel(@IntRange(from=0,to=10000) int level) {
if (mLevel != level) {
mLevel = level;
return onLevelChange(level);
@@ -742,7 +750,7 @@
*
* @return int Current level, from 0 (minimum) to 10000 (maximum).
*/
- public final int getLevel() {
+ public final @IntRange(from=0,to=10000) int getLevel() {
return mLevel;
}
@@ -839,7 +847,7 @@
*
* @see android.graphics.PixelFormat
*/
- public abstract int getOpacity();
+ public abstract @PixelFormat.Opacity int getOpacity();
/**
* Return the appropriate opacity value for two source opacities. If
@@ -856,7 +864,8 @@
*
* @see #getOpacity
*/
- public static int resolveOpacity(int op1, int op2) {
+ public static @PixelFormat.Opacity int resolveOpacity(@PixelFormat.Opacity int op1,
+ @PixelFormat.Opacity int op2) {
if (op1 == op2) {
return op1;
}
@@ -885,7 +894,7 @@
* report, else a Region holding the parts of the Drawable's bounds that
* are transparent.
*/
- public Region getTransparentRegion() {
+ public @Nullable Region getTransparentRegion() {
return null;
}
@@ -898,7 +907,10 @@
* if it looks the same and there is no need to redraw it since its
* last state.
*/
- protected boolean onStateChange(int[] state) { return false; }
+ protected boolean onStateChange(int[] state) {
+ return false;
+ }
+
/** Override this in your subclass to change appearance if you vary based
* on level.
* @return Returns true if the level change has caused the appearance of
@@ -906,12 +918,17 @@
* if it looks the same and there is no need to redraw it since its
* last level.
*/
- protected boolean onLevelChange(int level) { return false; }
+ protected boolean onLevelChange(int level) {
+ return false;
+ }
+
/**
* Override this in your subclass to change appearance if you vary based on
* the bounds.
*/
- protected void onBoundsChange(Rect bounds) {}
+ protected void onBoundsChange(Rect bounds) {
+ // Stub method.
+ }
/**
* Returns the drawable's intrinsic width.
@@ -986,7 +1003,7 @@
*
* @hide
*/
- public Insets getOpticalInsets() {
+ public @NonNull Insets getOpticalInsets() {
return Insets.NONE;
}
@@ -1020,7 +1037,7 @@
* @see ConstantState
* @see #getConstantState()
*/
- public Drawable mutate() {
+ public @NonNull Drawable mutate() {
return this;
}
@@ -1126,9 +1143,10 @@
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
- while ((type=parser.next()) != XmlPullParser.START_TAG &&
- type != XmlPullParser.END_DOCUMENT) {
- // Empty loop
+ //noinspection StatementWithEmptyBody
+ while ((type=parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Empty loop.
}
if (type != XmlPullParser.START_TAG) {
@@ -1222,8 +1240,9 @@
* @throws XmlPullParserException
* @throws IOException
*/
- void inflateWithAttributes(@NonNull Resources r, @NonNull XmlPullParser parser,
- @NonNull TypedArray attrs, int visibleAttr) throws XmlPullParserException, IOException {
+ void inflateWithAttributes(@NonNull @SuppressWarnings("unused") Resources r,
+ @NonNull @SuppressWarnings("unused") XmlPullParser parser, @NonNull TypedArray attrs,
+ @AttrRes int visibleAttr) throws XmlPullParserException, IOException {
mVisible = attrs.getBoolean(visibleAttr, mVisible);
}
@@ -1254,8 +1273,7 @@
* @return a new drawable object based on this constant state
* @see {@link #newDrawable(Resources)}
*/
- @NonNull
- public abstract Drawable newDrawable();
+ public abstract @NonNull Drawable newDrawable();
/**
* Creates a new Drawable instance from its constant state using the
@@ -1269,8 +1287,7 @@
* be displayed
* @return a new drawable object based on this constant state
*/
- @NonNull
- public Drawable newDrawable(@Nullable Resources res) {
+ public @NonNull Drawable newDrawable(@Nullable Resources res) {
return newDrawable();
}
@@ -1288,8 +1305,8 @@
* displayed
* @return a new drawable object based on this constant state
*/
- @NonNull
- public Drawable newDrawable(@Nullable Resources res, @Nullable Theme theme) {
+ public @NonNull Drawable newDrawable(@Nullable Resources res,
+ @Nullable @SuppressWarnings("unused") Theme theme) {
return newDrawable(res);
}
@@ -1303,12 +1320,12 @@
* @return Total pixel count
* @hide
*/
- public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+ public int addAtlasableBitmaps(@NonNull Collection<Bitmap> atlasList) {
return 0;
}
/** @hide */
- protected final boolean isAtlasable(Bitmap bitmap) {
+ protected final boolean isAtlasable(@Nullable Bitmap bitmap) {
return bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888;
}
@@ -1327,7 +1344,7 @@
* @see ConstantState
* @see Drawable#mutate()
*/
- public ConstantState getConstantState() {
+ public @Nullable ConstantState getConstantState() {
return null;
}
@@ -1345,8 +1362,8 @@
* Ensures the tint filter is consistent with the current tint color and
* mode.
*/
- PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint,
- PorterDuff.Mode tintMode) {
+ @Nullable PorterDuffColorFilter updateTintFilter(@Nullable PorterDuffColorFilter tintFilter,
+ @Nullable ColorStateList tint, @Nullable PorterDuff.Mode tintMode) {
if (tint == null || tintMode == null) {
return null;
}
@@ -1365,8 +1382,8 @@
* Obtains styled attributes from the theme, if available, or unstyled
* resources if the theme is null.
*/
- static TypedArray obtainAttributes(
- Resources res, Theme theme, AttributeSet set, int[] attrs) {
+ static @NonNull TypedArray obtainAttributes(@NonNull Resources res, @Nullable Theme theme,
+ @NonNull AttributeSet set, @NonNull int[] attrs) {
if (theme == null) {
return res.obtainAttributes(set, attrs);
}
@@ -1418,8 +1435,6 @@
final int rounded = Math.round(result);
if (rounded != 0) {
return rounded;
- } else if (pixels == 0) {
- return 0;
} else if (pixels > 0) {
return 1;
} else {
@@ -1440,7 +1455,7 @@
* @param cause the exception to re-throw
* @throws RuntimeException
*/
- static void rethrowAsRuntimeException(Exception cause) throws RuntimeException {
+ static void rethrowAsRuntimeException(@NonNull Exception cause) throws RuntimeException {
final RuntimeException e = new RuntimeException(cause);
e.setStackTrace(new StackTraceElement[0]);
throw e;
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index e75fb98..0e45780 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -534,13 +534,17 @@
public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
@NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
- if (mVectorState.mRootGroup != null || mVectorState.mNativeRendererRefBase != null) {
+ if (mVectorState.mRootGroup != null || mVectorState.mNativeTree != null) {
// This VD has been used to display other VD resource content, clean up.
- mVectorState.mRootGroup = new VGroup();
- if (mVectorState.mNativeRendererRefBase != null) {
- mVectorState.mNativeRendererRefBase.release();
+ if (mVectorState.mRootGroup != null) {
+ // Remove child nodes' reference to tree
+ mVectorState.mRootGroup.setTree(null);
}
- mVectorState.createNativeRenderer(mVectorState.mRootGroup.mNativePtr);
+ mVectorState.mRootGroup = new VGroup();
+ if (mVectorState.mNativeTree != null) {
+ mVectorState.mNativeTree.release();
+ }
+ mVectorState.createNativeTree(mVectorState.mRootGroup);
}
final VectorDrawableState state = mVectorState;
state.setDensity(Drawable.resolveDensity(r, 0));
@@ -734,7 +738,7 @@
Insets mOpticalInsets = Insets.NONE;
String mRootName = null;
VGroup mRootGroup;
- VirtualRefBasePtr mNativeRendererRefBase = null;
+ VirtualRefBasePtr mNativeTree = null;
int mDensity = DisplayMetrics.DENSITY_DEFAULT;
final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
@@ -755,7 +759,7 @@
mTintMode = copy.mTintMode;
mAutoMirrored = copy.mAutoMirrored;
mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
- createNativeRenderer(mRootGroup.mNativePtr);
+ createNativeTree(mRootGroup);
mBaseWidth = copy.mBaseWidth;
mBaseHeight = copy.mBaseHeight;
@@ -770,15 +774,16 @@
}
}
- private void createNativeRenderer(long rootGroupPtr) {
- mNativeRendererRefBase = new VirtualRefBasePtr(nCreateRenderer(rootGroupPtr));
+ private void createNativeTree(VGroup rootGroup) {
+ mNativeTree = new VirtualRefBasePtr(nCreateTree(rootGroup.mNativePtr));
+ mRootGroup.setTree(mNativeTree);
}
long getNativeRenderer() {
- if (mNativeRendererRefBase == null) {
+ if (mNativeTree == null) {
return 0;
}
- return mNativeRendererRefBase.get();
+ return mNativeTree.get();
}
public boolean canReuseCache() {
@@ -817,7 +822,7 @@
public VectorDrawableState() {
mRootGroup = new VGroup();
- createNativeRenderer(mRootGroup.mNativePtr);
+ createNativeTree(mRootGroup);
}
@Override
@@ -881,16 +886,16 @@
* has changed.
*/
public boolean setAlpha(float alpha) {
- return nSetRootAlpha(mNativeRendererRefBase.get(), alpha);
+ return nSetRootAlpha(mNativeTree.get(), alpha);
}
@SuppressWarnings("unused")
public float getAlpha() {
- return nGetRootAlpha(mNativeRendererRefBase.get());
+ return nGetRootAlpha(mNativeTree.get());
}
}
- static class VGroup implements VObject {
+ static class VGroup extends VObject {
private static final int ROTATE_INDEX = 0;
private static final int PIVOT_X_INDEX = 1;
private static final int PIVOT_Y_INDEX = 2;
@@ -984,11 +989,18 @@
public void addChild(VObject child) {
nAddChild(mNativePtr, child.getNativePtr());
mChildren.add(child);
-
mIsStateful |= child.isStateful();
}
@Override
+ public void setTree(VirtualRefBasePtr treeRoot) {
+ super.setTree(treeRoot);
+ for (int i = 0; i < mChildren.size(); i++) {
+ mChildren.get(i).setTree(treeRoot);
+ }
+ }
+
+ @Override
public long getNativePtr() {
return mNativePtr;
}
@@ -1101,79 +1113,93 @@
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@SuppressWarnings("unused")
public float getRotation() {
- return nGetRotation(mNativePtr);
+ return isTreeValid() ? nGetRotation(mNativePtr) : 0;
}
@SuppressWarnings("unused")
public void setRotation(float rotation) {
- nSetRotation(mNativePtr, rotation);
+ if (isTreeValid()) {
+ nSetRotation(mNativePtr, rotation);
+ }
}
@SuppressWarnings("unused")
public float getPivotX() {
- return nGetPivotX(mNativePtr);
+ return isTreeValid() ? nGetPivotX(mNativePtr) : 0;
}
@SuppressWarnings("unused")
public void setPivotX(float pivotX) {
- nSetPivotX(mNativePtr, pivotX);
+ if (isTreeValid()) {
+ nSetPivotX(mNativePtr, pivotX);
+ }
}
@SuppressWarnings("unused")
public float getPivotY() {
- return nGetPivotY(mNativePtr);
+ return isTreeValid() ? nGetPivotY(mNativePtr) : 0;
}
@SuppressWarnings("unused")
public void setPivotY(float pivotY) {
- nSetPivotY(mNativePtr, pivotY);
+ if (isTreeValid()) {
+ nSetPivotY(mNativePtr, pivotY);
+ }
}
@SuppressWarnings("unused")
public float getScaleX() {
- return nGetScaleX(mNativePtr);
+ return isTreeValid() ? nGetScaleX(mNativePtr) : 0;
}
@SuppressWarnings("unused")
public void setScaleX(float scaleX) {
- nSetScaleX(mNativePtr, scaleX);
+ if (isTreeValid()) {
+ nSetScaleX(mNativePtr, scaleX);
+ }
}
@SuppressWarnings("unused")
public float getScaleY() {
- return nGetScaleY(mNativePtr);
+ return isTreeValid() ? nGetScaleY(mNativePtr) : 0;
}
@SuppressWarnings("unused")
public void setScaleY(float scaleY) {
- nSetScaleY(mNativePtr, scaleY);
+ if (isTreeValid()) {
+ nSetScaleY(mNativePtr, scaleY);
+ }
}
@SuppressWarnings("unused")
public float getTranslateX() {
- return nGetTranslateX(mNativePtr);
+ return isTreeValid() ? nGetTranslateX(mNativePtr) : 0;
}
@SuppressWarnings("unused")
public void setTranslateX(float translateX) {
- nSetTranslateX(mNativePtr, translateX);
+ if (isTreeValid()) {
+ nSetTranslateX(mNativePtr, translateX);
+ }
}
@SuppressWarnings("unused")
public float getTranslateY() {
- return nGetTranslateY(mNativePtr);
+ return isTreeValid() ? nGetTranslateY(mNativePtr) : 0;
}
@SuppressWarnings("unused")
public void setTranslateY(float translateY) {
- nSetTranslateY(mNativePtr, translateY);
+ if (isTreeValid()) {
+ nSetTranslateY(mNativePtr, translateY);
+ }
}
}
/**
* Common Path information for clip path and normal path.
*/
- static abstract class VPath implements VObject {
+ static abstract class VPath extends VObject {
protected PathParser.PathData mPathData = null;
String mPathName;
@@ -1203,7 +1229,9 @@
@SuppressWarnings("unused")
public void setPathData(PathParser.PathData pathData) {
mPathData.setPathData(pathData);
- nSetPathData(getNativePtr(), mPathData.getNativePtr());
+ if (isTreeValid()) {
+ nSetPathData(getNativePtr(), mPathData.getNativePtr());
+ }
}
}
@@ -1549,97 +1577,120 @@
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@SuppressWarnings("unused")
int getStrokeColor() {
- return nGetStrokeColor(mNativePtr);
+ return isTreeValid() ? nGetStrokeColor(mNativePtr) : 0;
}
@SuppressWarnings("unused")
void setStrokeColor(int strokeColor) {
mStrokeColors = null;
- nSetStrokeColor(mNativePtr, strokeColor);
+ if (isTreeValid()) {
+ nSetStrokeColor(mNativePtr, strokeColor);
+ }
}
@SuppressWarnings("unused")
float getStrokeWidth() {
- return nGetStrokeWidth(mNativePtr);
+ return isTreeValid() ? nGetStrokeWidth(mNativePtr) : 0;
}
@SuppressWarnings("unused")
void setStrokeWidth(float strokeWidth) {
- nSetStrokeWidth(mNativePtr, strokeWidth);
+ if (isTreeValid()) {
+ nSetStrokeWidth(mNativePtr, strokeWidth);
+ }
}
@SuppressWarnings("unused")
float getStrokeAlpha() {
- return nGetStrokeAlpha(mNativePtr);
+ return isTreeValid() ? nGetStrokeAlpha(mNativePtr) : 0;
}
@SuppressWarnings("unused")
void setStrokeAlpha(float strokeAlpha) {
- nSetStrokeAlpha(mNativePtr, strokeAlpha);
+ if (isTreeValid()) {
+ nSetStrokeAlpha(mNativePtr, strokeAlpha);
+ }
}
@SuppressWarnings("unused")
int getFillColor() {
- return nGetFillColor(mNativePtr);
+ return isTreeValid() ? nGetFillColor(mNativePtr) : 0;
}
@SuppressWarnings("unused")
void setFillColor(int fillColor) {
mFillColors = null;
- nSetFillColor(mNativePtr, fillColor);
+ if (isTreeValid()) {
+ nSetFillColor(mNativePtr, fillColor);
+ }
}
@SuppressWarnings("unused")
float getFillAlpha() {
- return nGetFillAlpha(mNativePtr);
+ return isTreeValid() ? nGetFillAlpha(mNativePtr) : 0;
}
@SuppressWarnings("unused")
void setFillAlpha(float fillAlpha) {
- nSetFillAlpha(mNativePtr, fillAlpha);
+ if (isTreeValid()) {
+ nSetFillAlpha(mNativePtr, fillAlpha);
+ }
}
@SuppressWarnings("unused")
float getTrimPathStart() {
- return nGetTrimPathStart(mNativePtr);
+ return isTreeValid() ? nGetTrimPathStart(mNativePtr) : 0;
}
@SuppressWarnings("unused")
void setTrimPathStart(float trimPathStart) {
- nSetTrimPathStart(mNativePtr, trimPathStart);
+ if (isTreeValid()) {
+ nSetTrimPathStart(mNativePtr, trimPathStart);
+ }
}
@SuppressWarnings("unused")
float getTrimPathEnd() {
- return nGetTrimPathEnd(mNativePtr);
+ return isTreeValid() ? nGetTrimPathEnd(mNativePtr) : 0;
}
@SuppressWarnings("unused")
void setTrimPathEnd(float trimPathEnd) {
- nSetTrimPathEnd(mNativePtr, trimPathEnd);
+ if (isTreeValid()) {
+ nSetTrimPathEnd(mNativePtr, trimPathEnd);
+ }
}
@SuppressWarnings("unused")
float getTrimPathOffset() {
- return nGetTrimPathOffset(mNativePtr);
+ return isTreeValid() ? nGetTrimPathOffset(mNativePtr) : 0;
}
@SuppressWarnings("unused")
void setTrimPathOffset(float trimPathOffset) {
- nSetTrimPathOffset(mNativePtr, trimPathOffset);
+ if (isTreeValid()) {
+ nSetTrimPathOffset(mNativePtr, trimPathOffset);
+ }
}
}
- interface VObject {
- long getNativePtr();
- void inflate(Resources r, AttributeSet attrs, Theme theme);
- boolean canApplyTheme();
- void applyTheme(Theme t);
- boolean onStateChange(int[] state);
- boolean isStateful();
+ abstract static class VObject {
+ VirtualRefBasePtr mTreePtr = null;
+ boolean isTreeValid() {
+ return mTreePtr != null && mTreePtr.get() != 0;
+ }
+ void setTree(VirtualRefBasePtr ptr) {
+ mTreePtr = ptr;
+ }
+ abstract long getNativePtr();
+ abstract void inflate(Resources r, AttributeSet attrs, Theme theme);
+ abstract boolean canApplyTheme();
+ abstract void applyTheme(Theme t);
+ abstract boolean onStateChange(int[] state);
+ abstract boolean isStateful();
}
- private static native long nCreateRenderer(long rootGroupPtr);
+ private static native long nCreateTree(long rootGroupPtr);
private static native void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
float viewportHeight);
private static native boolean nSetRootAlpha(long rendererPtr, float alpha);
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 6913f43..715c875 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -34,9 +34,7 @@
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Timers.h>
-#ifdef __ANDROID__
-#include <cutils/trace.h>
-#endif
+#include <utils/Trace.h>
#include <assert.h>
#include <dirent.h>
@@ -54,14 +52,6 @@
_rc; })
#endif
-#ifdef __ANDROID__
-#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x)
-#define MY_TRACE_END() ATRACE_END()
-#else
-#define MY_TRACE_BEGIN(x)
-#define MY_TRACE_END()
-#endif
-
using namespace android;
static const bool kIsDebug = false;
@@ -623,7 +613,7 @@
ResTable* sharedRes = NULL;
bool shared = true;
bool onlyEmptyResources = true;
- MY_TRACE_BEGIN(ap.path.string());
+ ATRACE_NAME(ap.path.string());
Asset* idmap = openIdmapLocked(ap);
size_t nextEntryIdx = mResources->getTableCount();
ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
@@ -703,8 +693,6 @@
if (idmap != NULL) {
delete idmap;
}
- MY_TRACE_END();
-
return onlyEmptyResources;
}
@@ -752,6 +740,7 @@
void AssetManager::updateResourceParamsLocked() const
{
+ ATRACE_CALL();
ResTable* res = mResources;
if (!res) {
return;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 1ccc59a..15cb684 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include <string.h>
+#include <algorithm>
#include <limits>
#include <memory>
#include <type_traits>
@@ -5810,6 +5811,10 @@
return NULL;
}
+static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) {
+ return a.compare(b) < 0;
+}
+
void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
bool ignoreAndroidPackage, bool includeSystemConfigs) const {
const size_t packageCount = mPackageGroups.size();
@@ -5840,17 +5845,11 @@
ResTable_config cfg;
memset(&cfg, 0, sizeof(ResTable_config));
cfg.copyFromDtoH(config->config);
- // only insert unique
- const size_t N = configs->size();
- size_t n;
- for (n = 0; n < N; n++) {
- if (0 == (*configs)[n].compare(cfg)) {
- break;
- }
- }
- // if we didn't find it
- if (n == N) {
- configs->add(cfg);
+
+ auto iter = std::lower_bound(configs->begin(), configs->end(), cfg,
+ compareResTableConfig);
+ if (iter == configs->end() || iter->compare(cfg) != 0) {
+ configs->insertAt(cfg, std::distance(configs->begin(), iter));
}
}
}
@@ -5858,6 +5857,10 @@
}
}
+static bool compareString8AndCString(const String8& str, const char* cStr) {
+ return strcmp(str.string(), cStr) < 0;
+}
+
void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
{
Vector<ResTable_config> configs;
@@ -5872,15 +5875,11 @@
char locale[RESTABLE_MAX_LOCALE_LEN];
for (size_t i=0; i<I; i++) {
configs[i].getBcp47Locale(locale);
- const size_t J = locales->size();
- size_t j;
- for (j=0; j<J; j++) {
- if (0 == strcmp(locale, (*locales)[j].string())) {
- break;
- }
- }
- if (j == J) {
- locales->add(String8(locale));
+
+ auto iter = std::lower_bound(locales->begin(), locales->end(), locale,
+ compareString8AndCString);
+ if (iter == locales->end() || strcmp(iter->string(), locale) != 0) {
+ locales->insertAt(String8(locale), std::distance(locales->begin(), iter));
}
}
}
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 7cd7fb5..b8b4625 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -39,8 +39,20 @@
*/
#include "data/basic/basic_arsc.h"
+/**
+ * Include a binary library resource table.
+ *
+ * Package: com.android.test.basic
+ */
#include "data/lib/lib_arsc.h"
+/**
+ * Include a system resource table.
+ *
+ * Package: android
+ */
+#include "data/system/system_arsc.h"
+
TEST(ResTableTest, shouldLoadSuccessfully) {
ResTable table;
ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
@@ -324,4 +336,25 @@
ASSERT_EQ(uint32_t(600), val.data);
}
+TEST(ResTableTest, GetConfigurationsReturnsUniqueList) {
+ ResTable table;
+ ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len));
+ ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+ ResTable_config configSv;
+ memset(&configSv, 0, sizeof(configSv));
+ configSv.language[0] = 's';
+ configSv.language[1] = 'v';
+
+ Vector<ResTable_config> configs;
+ table.getConfigurations(&configs);
+
+ EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv));
+
+ Vector<String8> locales;
+ table.getLocales(&locales);
+
+ EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv")));
+}
+
} // namespace
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index ac80d88..ff9be16 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -21,7 +21,7 @@
enum { MAY_NOT_BE_BAG = false };
static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) {
- return memcmp(&a, &b, sizeof(a)) == 0;
+ return a.compare(b) == 0;
}
static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) {
diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h
index 27f25fe..6a31fb8 100644
--- a/libs/androidfw/tests/data/system/R.h
+++ b/libs/androidfw/tests/data/system/R.h
@@ -33,6 +33,12 @@
};
}
+namespace integer {
+ enum {
+ number = 0x01030000, // sv
+ };
+}
+
} // namespace R
} // namespace android
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml
similarity index 70%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
copy to libs/androidfw/tests/data/system/res/values-sv/values.xml
index 681ff91..b97bdb6 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/libs/androidfw/tests/data/system/res/values-sv/values.xml
@@ -14,8 +14,7 @@
limitations under the License.
-->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:propertyName="alpha"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+<resources>
+ <public type="integer" name="number" id="0x01030000" />
+ <integer name="number">1</integer>
+</resources>
diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h
index 215ecae..b0dab6b 100644
--- a/libs/androidfw/tests/data/system/system_arsc.h
+++ b/libs/androidfw/tests/data/system/system_arsc.h
@@ -1,8 +1,8 @@
unsigned char system_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd0, 0x03, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -25,26 +25,33 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
- 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
- 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
- 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x5e, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x70, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00,
0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00,
0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
- 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
- 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00,
+ 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -55,15 +62,27 @@
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00,
- 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00,
+ 0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff,
- 0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x10, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x60, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned int system_arsc_len = 792;
+unsigned int system_arsc_len = 1016;
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index bd71e0d..4d65782 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -226,7 +226,7 @@
// Set to 0 so that the animate() basically instantly finishes
mStartTime = 0;
}
- if (mDuration < 0 || mDuration > 50000) {
+ if (mDuration < 0) {
ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
}
}
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index d1ff670..9d4eccc 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -285,6 +285,7 @@
void JankTracker::reset() {
mData->jankTypeCounts.fill(0);
mData->frameCounts.fill(0);
+ mData->slowFrameCounts.fill(0);
mData->totalFrameCount = 0;
mData->jankFrameCount = 0;
mData->statStartTime = systemTime(CLOCK_MONOTONIC);
diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp
index 7e85333..2179f14 100644
--- a/libs/hwui/PathParser.cpp
+++ b/libs/hwui/PathParser.cpp
@@ -162,7 +162,7 @@
|| verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
}
-void PathParser::getPathDataFromString(PathData* data, ParseResult* result,
+void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
const char* pathStr, size_t strLen) {
if (pathStr == NULL) {
result->failureOccurred = true;
@@ -171,7 +171,16 @@
}
size_t start = 0;
- size_t end = 1;
+ // Skip leading spaces.
+ while (isspace(pathStr[start]) && start < strLen) {
+ start++;
+ }
+ if (start == strLen) {
+ result->failureOccurred = true;
+ result->failureMessage = "Path string cannot be empty.";
+ return;
+ }
+ size_t end = start + 1;
while (end < strLen) {
end = nextStart(pathStr, strLen, end);
@@ -226,9 +235,9 @@
ALOGD("points are : %s", os.str().c_str());
}
-void PathParser::parseStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
+void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
PathData pathData;
- getPathDataFromString(&pathData, result, pathStr, strLen);
+ getPathDataFromAsciiString(&pathData, result, pathStr, strLen);
if (result->failureOccurred) {
return;
}
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 180a7a3..5578e8d 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -39,9 +39,9 @@
/**
* Parse the string literal and create a Skia Path. Return true on success.
*/
- ANDROID_API static void parseStringForSkPath(SkPath* outPath, ParseResult* result,
+ ANDROID_API static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result,
const char* pathStr, size_t strLength);
- ANDROID_API static void getPathDataFromString(PathData* outData, ParseResult* result,
+ ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
const char* pathStr, size_t strLength);
static void dump(const PathData& data);
static bool isVerbValid(char verb);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index adfe45c..ac17ed2 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -96,7 +96,7 @@
Path::Path(const char* pathStr, size_t strLength) {
PathParser::ParseResult result;
Data data;
- PathParser::getPathDataFromString(&data, &result, pathStr, strLength);
+ PathParser::getPathDataFromAsciiString(&data, &result, pathStr, strLength);
mStagingProperties.setData(data);
}
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index e4c7ed7..691cfa01 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -40,11 +40,11 @@
namespace uirenderer {
namespace VectorDrawable {
-#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP_AND_NOTIFY(field, value) ? (flag = true, true) : false)
-#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
-#define VD_SET_PROP_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP(field, value);\
+#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
+#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
+#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
onPropertyChanged(); retVal;})
-#define UPDATE_SKPROP(field, value) ({bool retVal = (field != value); if (field != value) SkRefCnt_SafeAssign(field, value); retVal;})
+#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
/* A VectorDrawable is composed of a tree of nodes.
* Each node can be a group node, or a path.
@@ -248,49 +248,49 @@
return mPrimitiveFields.strokeWidth;
}
void setStrokeWidth(float strokeWidth) {
- VD_SET_PROP_AND_NOTIFY(strokeWidth, strokeWidth);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
}
SkColor getStrokeColor() const{
return mPrimitiveFields.strokeColor;
}
void setStrokeColor(SkColor strokeColor) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeColor, strokeColor);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
}
float getStrokeAlpha() const{
return mPrimitiveFields.strokeAlpha;
}
void setStrokeAlpha(float strokeAlpha) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeAlpha, strokeAlpha);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
}
SkColor getFillColor() const {
return mPrimitiveFields.fillColor;
}
void setFillColor(SkColor fillColor) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillColor, fillColor);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
}
float getFillAlpha() const{
return mPrimitiveFields.fillAlpha;
}
void setFillAlpha(float fillAlpha) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillAlpha, fillAlpha);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
}
float getTrimPathStart() const{
return mPrimitiveFields.trimPathStart;
}
void setTrimPathStart(float trimPathStart) {
- VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathStart, trimPathStart, mTrimDirty);
+ VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
}
float getTrimPathEnd() const{
return mPrimitiveFields.trimPathEnd;
}
void setTrimPathEnd(float trimPathEnd) {
- VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathEnd, trimPathEnd, mTrimDirty);
+ VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
}
float getTrimPathOffset() const{
return mPrimitiveFields.trimPathOffset;
}
void setTrimPathOffset(float trimPathOffset) {
- VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathOffset, trimPathOffset, mTrimDirty);
+ VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
}
float getStrokeMiterLimit() const {
@@ -425,43 +425,43 @@
return mPrimitiveFields.rotate;
}
void setRotation(float rotation) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.rotate, rotation);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
}
float getPivotX() const {
return mPrimitiveFields.pivotX;
}
void setPivotX(float pivotX) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotX, pivotX);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
}
float getPivotY() const {
return mPrimitiveFields.pivotY;
}
void setPivotY(float pivotY) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotY, pivotY);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
}
float getScaleX() const {
return mPrimitiveFields.scaleX;
}
void setScaleX(float scaleX) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleX, scaleX);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
}
float getScaleY() const {
return mPrimitiveFields.scaleY;
}
void setScaleY(float scaleY) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleY, scaleY);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
}
float getTranslateX() const {
return mPrimitiveFields.translateX;
}
void setTranslateX(float translateX) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.translateX, translateX);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
}
float getTranslateY() const {
return mPrimitiveFields.translateY;
}
void setTranslateY(float translateY) {
- VD_SET_PROP_AND_NOTIFY(translateY, translateY);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
}
void updateProperties(float rotate, float pivotX, float pivotY,
float scaleX, float scaleY, float translateX, float translateY) {
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index 4186539..b43c4c3 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -31,7 +31,7 @@
size_t length = strlen(sPathString);
PathParser::ParseResult result;
while (state.KeepRunning()) {
- PathParser::parseStringForSkPath(&skPath, &result, sPathString, length);
+ PathParser::parseAsciiStringForSkPath(&skPath, &result, sPathString, length);
benchmark::DoNotOptimize(&result);
benchmark::DoNotOptimize(&skPath);
}
@@ -43,7 +43,7 @@
PathData outData;
PathParser::ParseResult result;
while (state.KeepRunning()) {
- PathParser::getPathDataFromString(&outData, &result, sPathString, length);
+ PathParser::getPathDataFromAsciiString(&outData, &result, sPathString, length);
benchmark::DoNotOptimize(&result);
benchmark::DoNotOptimize(&outData);
}
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 796169e..83b485f 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -234,9 +234,10 @@
{"3e...3", false}, // Not starting with a verb and ill-formatted float
{"L.M.F.A.O", false}, // No floats following verbs
{"m 1 1", true}, // Valid path data
- {"z", true}, // Valid path data
+ {"\n \t z", true}, // Valid path data with leading spaces
{"1-2e34567", false}, // Not starting with a verb and ill-formatted float
- {"f 4 5", false} // Invalid verb
+ {"f 4 5", false}, // Invalid verb
+ {"\r ", false} // Empty string
};
@@ -250,7 +251,7 @@
// Test generated path data against the given data.
PathData pathData;
size_t length = strlen(testData.pathString);
- PathParser::getPathDataFromString(&pathData, &result, testData.pathString, length);
+ PathParser::getPathDataFromAsciiString(&pathData, &result, testData.pathString, length);
EXPECT_EQ(testData.pathData, pathData);
}
@@ -258,7 +259,7 @@
PathParser::ParseResult result;
PathData pathData;
SkPath skPath;
- PathParser::getPathDataFromString(&pathData, &result,
+ PathParser::getPathDataFromAsciiString(&pathData, &result,
stringPath.stringPath, strlen(stringPath.stringPath));
EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
}
@@ -274,13 +275,13 @@
}
}
-TEST(PathParser, parseStringForSkPath) {
+TEST(PathParser, parseAsciiStringForSkPath) {
for (TestData testData: sTestDataSet) {
PathParser::ParseResult result;
size_t length = strlen(testData.pathString);
// Check the return value as well as the SkPath generated.
SkPath actualPath;
- PathParser::parseStringForSkPath(&actualPath, &result, testData.pathString, length);
+ PathParser::parseAsciiStringForSkPath(&actualPath, &result, testData.pathString, length);
bool hasValidData = !result.failureOccurred;
EXPECT_EQ(hasValidData, testData.pathData.verbs.size() > 0);
SkPath expectedPath;
@@ -291,7 +292,7 @@
for (StringPath stringPath : sStringPaths) {
PathParser::ParseResult result;
SkPath skPath;
- PathParser::parseStringForSkPath(&skPath, &result, stringPath.stringPath,
+ PathParser::parseAsciiStringForSkPath(&skPath, &result, stringPath.stringPath,
strlen(stringPath.stringPath));
EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
}
@@ -390,5 +391,40 @@
EXPECT_EQ(matrixAndScale.matrixScale, actualMatrixScale);
}
}
+
+TEST(VectorDrawable, groupProperties) {
+ //TODO: Also need to test property sync and dirty flag when properties change.
+ VectorDrawable::Group group;
+ VectorDrawable::Group::GroupProperties* properties = group.mutateProperties();
+ // Test default values, change values through setters and verify the change through getters.
+ EXPECT_EQ(0.0f, properties->getTranslateX());
+ properties->setTranslateX(1.0f);
+ EXPECT_EQ(1.0f, properties->getTranslateX());
+
+ EXPECT_EQ(0.0f, properties->getTranslateY());
+ properties->setTranslateY(1.0f);
+ EXPECT_EQ(1.0f, properties->getTranslateY());
+
+ EXPECT_EQ(0.0f, properties->getRotation());
+ properties->setRotation(1.0f);
+ EXPECT_EQ(1.0f, properties->getRotation());
+
+ EXPECT_EQ(1.0f, properties->getScaleX());
+ properties->setScaleX(0.0f);
+ EXPECT_EQ(0.0f, properties->getScaleX());
+
+ EXPECT_EQ(1.0f, properties->getScaleY());
+ properties->setScaleY(0.0f);
+ EXPECT_EQ(0.0f, properties->getScaleY());
+
+ EXPECT_EQ(0.0f, properties->getPivotX());
+ properties->setPivotX(1.0f);
+ EXPECT_EQ(1.0f, properties->getPivotX());
+
+ EXPECT_EQ(0.0f, properties->getPivotY());
+ properties->setPivotY(1.0f);
+ EXPECT_EQ(1.0f, properties->getPivotY());
+
+}
}; // namespace uirenderer
}; // namespace android
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index a5550ec..4504e69 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -876,22 +876,24 @@
* Calling {@link #startRecording()} following a {@link #stop()} will reset
* the frame count to 0.
*
- * @param timestamp a reference to a non-null AudioTimestamp instance.
+ * @param outTimestamp a caller provided non-null AudioTimestamp instance,
+ * which is updated with the AudioRecord frame delivery information upon success.
* @param timebase one of
* {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or
- * {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC}.
+ * {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC},
+ * used to select the clock for the AudioTimestamp time.
* @return {@link #SUCCESS} if a timestamp is available,
* or {@link #ERROR_INVALID_OPERATION} if a timestamp not available.
*/
- public int getTimestamp(@NonNull AudioTimestamp timestamp,
+ public int getTimestamp(@NonNull AudioTimestamp outTimestamp,
@AudioTimestamp.Timebase int timebase)
{
- if (timestamp == null ||
+ if (outTimestamp == null ||
(timebase != AudioTimestamp.TIMEBASE_BOOTTIME
&& timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) {
throw new IllegalArgumentException();
}
- return native_get_timestamp(timestamp, timebase);
+ return native_get_timestamp(outTimestamp, timebase);
}
/**
@@ -1725,7 +1727,7 @@
private native final void native_enableDeviceCallback();
private native final void native_disableDeviceCallback();
- private native final int native_get_timestamp(@NonNull AudioTimestamp timestamp,
+ private native final int native_get_timestamp(@NonNull AudioTimestamp outTimestamp,
@AudioTimestamp.Timebase int timebase);
//---------------------------------------------------------
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 03dc699..a33b219 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -16,7 +16,9 @@
package android.media.tv;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.StringRes;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
@@ -48,6 +50,8 @@
import java.io.IOException;
import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
@@ -62,6 +66,12 @@
private static final boolean DEBUG = false;
private static final String TAG = "TvInputInfo";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({TYPE_TUNER, TYPE_OTHER, TYPE_COMPOSITE, TYPE_SVIDEO, TYPE_SCART, TYPE_COMPONENT,
+ TYPE_VGA, TYPE_DVI, TYPE_HDMI, TYPE_DISPLAY_PORT})
+ public @interface Type {}
+
// Should be in sync with frameworks/base/core/res/res/values/attrs.xml
/**
* TV input type: the TV input service is a tuner which provides channels.
@@ -343,6 +353,7 @@
/**
* Returns the type of this TV input.
*/
+ @Type
public int getType() {
return mType;
}
@@ -369,8 +380,7 @@
}
/**
- * Returns the extras associated with this TV input.
- * @hide
+ * Returns domain-specific extras associated with this TV input.
*/
public Bundle getExtras() {
return mExtras;
@@ -769,7 +779,7 @@
* @hide
*/
@SystemApi
- public Builder setLabel(int resId) {
+ public Builder setLabel(@StringRes int resId) {
if (mLabel != null) {
throw new IllegalStateException("Label text is already set.");
}
@@ -847,11 +857,12 @@
}
/**
- * Sets the extras associated with this TV input.
+ * Sets domain-specific extras associated with this TV input.
*
- * @param extras The extras associated with this TV input.
+ * @param extras Domain-specific extras associated with this TV input. Keys <em>must</em> be
+ * a scoped name, i.e. prefixed with a package name you own, so that different
+ * developers will not create conflicting keys.
* @return This Builder object to allow for chaining of calls to builder methods.
- * @hide
*/
public Builder setExtras(Bundle extras) {
this.mExtras = extras;
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index b4536b1..d74dda6 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -99,6 +99,13 @@
*/
public static final int DVB_DEVICE_FRONTEND = DVB_DEVICE_END;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
+ VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
+ VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY})
+ public @interface VideoUnavailableReason {}
+
static final int VIDEO_UNAVAILABLE_REASON_START = 0;
static final int VIDEO_UNAVAILABLE_REASON_END = 4;
@@ -135,10 +142,9 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
- VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
- VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY})
- public @interface VideoUnavailableReason {}
+ @IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
+ TIME_SHIFT_STATUS_UNAVAILABLE, TIME_SHIFT_STATUS_AVAILABLE})
+ public @interface TimeShiftStatus {}
/**
* Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
@@ -169,12 +175,6 @@
*/
public static final int TIME_SHIFT_STATUS_AVAILABLE = 3;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
- TIME_SHIFT_STATUS_UNAVAILABLE, TIME_SHIFT_STATUS_AVAILABLE})
- public @interface TimeShiftStatus {}
-
/**
* Value returned by {@link TvInputService.Session#onTimeShiftGetCurrentPosition()} and
* {@link TvInputService.Session#onTimeShiftGetStartPosition()} when time shifting has not
@@ -182,6 +182,12 @@
*/
public static final long TIME_SHIFT_INVALID_TIME = Long.MIN_VALUE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_INSUFFICIENT_SPACE,
+ RECORDING_ERROR_RESOURCE_BUSY})
+ public @interface RecordingError {}
+
/**
* Error for {@link TvInputService.RecordingSession#notifyError(int)} and
* {@link TvRecordingClient.RecordingCallback#onError(int)}: The requested operation cannot be
@@ -205,9 +211,8 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_INSUFFICIENT_SPACE,
- RECORDING_ERROR_RESOURCE_BUSY})
- public @interface RecordingError {}
+ @IntDef({INPUT_STATE_CONNECTED, INPUT_STATE_CONNECTED_STANDBY, INPUT_STATE_DISCONNECTED})
+ public @interface InputState {}
/**
* State for {@link #getInputState(String)} and
@@ -240,11 +245,6 @@
*/
public static final int INPUT_STATE_DISCONNECTED = 2;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({INPUT_STATE_CONNECTED, INPUT_STATE_CONNECTED_STANDBY, INPUT_STATE_DISCONNECTED})
- public @interface InputState {}
-
/**
* Broadcast intent action when the user blocked content ratings change. For use with the
* {@link #isRatingBlocked}.
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 97ef6d8..3780f6f 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.FloatRange;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -823,7 +824,7 @@
*
* @param volume A volume value between {@code 0.0f} to {@code 1.0f}.
*/
- public abstract void onSetStreamVolume(float volume);
+ public abstract void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume);
/**
* Tunes to a given channel.
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index d718a7e..c9c881c 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Bundle;
import android.os.Parcel;
@@ -24,12 +25,20 @@
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
* Encapsulates the format of tracks played in {@link TvInputService}.
*/
public final class TvTrackInfo implements Parcelable {
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({TYPE_AUDIO, TYPE_VIDEO, TYPE_SUBTITLE})
+ public @interface Type {}
+
/**
* The type value for audio tracks.
*/
@@ -96,6 +105,7 @@
* Returns the type of the track. The type should be one of the followings:
* {@link #TYPE_AUDIO}, {@link #TYPE_VIDEO} and {@link #TYPE_SUBTITLE}.
*/
+ @Type
public final int getType() {
return mType;
}
@@ -319,7 +329,7 @@
* @throws IllegalArgumentException if the type is not any of {@link #TYPE_AUDIO},
* {@link #TYPE_VIDEO} and {@link #TYPE_SUBTITLE}
*/
- public Builder(int type, @NonNull String id) {
+ public Builder(@Type int type, @NonNull String id) {
if (type != TYPE_AUDIO
&& type != TYPE_VIDEO
&& type != TYPE_SUBTITLE) {
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 02ee0cc..71b0193 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -271,7 +272,7 @@
*
* @param volume A volume value between {@code 0.0f} to {@code 1.0f}.
*/
- public void setStreamVolume(float volume) {
+ public void setStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume) {
if (DEBUG) Log.d(TAG, "setStreamVolume(" + volume + ")");
mStreamVolume = volume;
if (mSession == null) {
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h
index d388388..9096aeb 100644
--- a/media/jni/soundpool/SoundPoolThread.h
+++ b/media/jni/soundpool/SoundPoolThread.h
@@ -47,7 +47,7 @@
void write(SoundPoolMsg msg);
private:
- static const size_t maxMessages = 5;
+ static const size_t maxMessages = 128;
static int beginThread(void* arg);
int run();
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index 3197abd..568e200 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -2,6 +2,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
+LOCAL_PRIVILEGED_MODULE := true
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
index f6fe47b..3373c23 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
@@ -147,17 +147,13 @@
}
}
- // Hamburger if drawer is present, else root icon, or sad nullness.
+ // Hamburger if drawer is present, else sad nullness.
private @Nullable Drawable getActionBarIcon() {
if (mDrawer.isPresent()) {
return mToolbar.getContext().getDrawable(R.drawable.ic_hamburger);
} else {
- RootInfo root = mEnv.getCurrentRoot();
- if (root != null) {
- return root.loadToolbarIcon(mToolbar.getContext());
- }
+ return null;
}
- return null;
}
void revealRootsDrawer(boolean open) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 8fcd9d1..babde99 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -17,7 +17,6 @@
package com.android.documentsui;
import static com.android.documentsui.Shared.DEBUG;
-import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
import android.content.ClipData;
@@ -45,6 +44,8 @@
* Provides support for gather a list of quick-viewable files into a quick view intent.
*/
final class QuickViewIntentBuilder {
+
+ private static final String TAG = "QuickViewIntentBuilder";
private static final int MAX_CLIP_ITEMS = 1000;
private final DocumentInfo mDocument;
@@ -127,8 +128,18 @@
for (int i = 0; i < siblingIds.length; i++) {
cursor = mModel.getItem(siblingIds[i]);
+ if (cursor == null) {
+ if (DEBUG) Log.d(TAG,
+ "Unable to obtain cursor for sibling document, modelId: "
+ + siblingIds[i]);
+ continue;
+ }
+
mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+ if (DEBUG) Log.d(TAG,
+ "Skipping directory, not supported by quick view. modelId: "
+ + siblingIds[i]);
continue;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index f3b750a..d830c61 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -84,6 +84,13 @@
new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
+ // Only handle key-down events. This is simpler, consistent with most other
+ // UIs, and enables the handling of repeated key events from holding down a
+ // key.
+ if (event.getAction() != KeyEvent.ACTION_DOWN) {
+ return false;
+ }
+
if (keyCode == KeyEvent.KEYCODE_ENTER && mSave.isEnabled()) {
performSave();
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index aa9f356..22454ad 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -351,7 +351,10 @@
private boolean handleViewItem(String id) {
final Cursor cursor = mModel.getItem(id);
- assert(cursor != null);
+ if (cursor == null) {
+ Log.w(TAG, "Can't view item. Can't obtain cursor for modeId" + id);
+ return false;
+ }
final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
@@ -465,11 +468,14 @@
public boolean onBeforeItemStateChange(String modelId, boolean selected) {
if (selected) {
final Cursor cursor = mModel.getItem(modelId);
-
- assert(cursor != null);
+ if (cursor == null) {
+ Log.w(TAG, "Can't obtain cursor for modelId: " + modelId);
+ return false;
+ }
final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+
return mTuner.canSelectType(docMimeType, docFlags);
}
return true;
@@ -479,7 +485,7 @@
public void onItemStateChanged(String modelId, boolean selected) {
final Cursor cursor = mModel.getItem(modelId);
if (cursor == null) {
- Log.e(TAG, "Model returned null cursor for document: " + modelId
+ Log.w(TAG, "Model returned null cursor for document: " + modelId
+ ". Ignoring state changed event.");
return;
}
@@ -518,6 +524,7 @@
}
if (mActionMode != null) {
+ assert(!mSelected.isEmpty());
final String title = Shared.getQuantityString(getActivity(),
R.plurals.elements_selected, mSelected.size());
mActionMode.setTitle(title);
@@ -803,6 +810,8 @@
// the user cancels the delete.
if (mActionMode != null) {
mActionMode.finish();
+ } else {
+ Log.w(TAG, "Action mode is null before deleting documents.");
}
// Hide the files in the UI...since the operation
// might be queued up on FileOperationService.
@@ -1104,6 +1113,10 @@
List<String> enabled = new ArrayList<String>();
for (String id : mAdapter.getModelIds()) {
Cursor cursor = getModel().getItem(id);
+ if (cursor == null) {
+ Log.w(TAG, "Skipping selection. Can't obtain cursor for modeId: " + id);
+ continue;
+ }
String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
if (isDocumentEnabled(docMimeType, docFlags)) {
@@ -1192,7 +1205,10 @@
String id = getModelId(v);
if (id != null) {
Cursor dstCursor = mModel.getItem(id);
- assert(dstCursor != null);
+ if (dstCursor == null) {
+ Log.w(TAG, "Invalid destination. Can't obtain cursor for modelId: " + id);
+ return null;
+ }
return DocumentInfo.fromDirectoryCursor(dstCursor);
}
@@ -1265,8 +1281,10 @@
}
final Cursor cursor = mModel.getItem(modelId);
-
- assert(cursor != null);
+ if (cursor == null) {
+ Log.w(TAG, "Undraggable document. Can't obtain cursor for modelId " + modelId);
+ return Collections.EMPTY_LIST;
+ }
return Lists.newArrayList(
DocumentInfo.fromDirectoryCursor(cursor));
@@ -1395,7 +1413,7 @@
// Handle range selection adjustments. Extending the selection will adjust the
// bounds of the in-progress range selection. Each time an unshifted navigation
// event is received, the range selection is restarted.
- if (shouldExtendSelection(event)) {
+ if (shouldExtendSelection(doc, event)) {
if (!mSelectionManager.isRangeSelectionActive()) {
// Start a range selection if one isn't active
mSelectionManager.startRangeSelection(doc.getAdapterPosition());
@@ -1421,7 +1439,8 @@
// This has to be handled here instead of in a keyboard shortcut, because
// keyboard shortcuts all have to be modified with the 'Ctrl' key.
if (mSelectionManager.hasSelection()) {
- deleteDocuments(mSelectionManager.getSelection());
+ Selection selection = mSelectionManager.getSelection(new Selection());
+ deleteDocuments(selection);
}
// Always handle the key, even if there was nothing to delete. This is a
// precaution to prevent other handlers from potentially picking up the event
@@ -1432,9 +1451,22 @@
return false;
}
- private boolean shouldExtendSelection(KeyEvent event) {
- return Events.isNavigationKeyCode(event.getKeyCode()) &&
- event.isShiftPressed();
+ private boolean shouldExtendSelection(DocumentHolder doc, KeyEvent event) {
+ if (!Events.isNavigationKeyCode(event.getKeyCode()) || !event.isShiftPressed()) {
+ return false;
+ }
+
+ // TODO: Combine this method with onBeforeItemStateChange, as both of them are almost
+ // the same, and responsible for the same thing (whether to select or not).
+ final Cursor cursor = mModel.getItem(doc.modelId);
+ if (cursor == null) {
+ Log.w(TAG, "Couldn't obtain cursor for modelId: " + doc.modelId);
+ return false;
+ }
+
+ final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+ return mTuner.canSelectType(docMimeType, docFlags);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
index ac05c05..f274df3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.database.Cursor;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
@@ -476,9 +477,9 @@
List<String> index = new ArrayList<>(itemCount);
for (int i = 0; i < itemCount; i++) {
String modelId = mAdapter.getModelId(i);
- if (modelId != null) {
- String title =
- getCursorString(mModel.getItem(modelId), Document.COLUMN_DISPLAY_NAME);
+ Cursor cursor = mModel.getItem(modelId);
+ if (modelId != null && cursor != null) {
+ String title = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
// Perform case-insensitive search.
index.add(title.toLowerCase());
} else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index 016cc9e..e6217b2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -195,6 +195,10 @@
*/
private static final class FilesTuner extends FragmentTuner {
+ // We use this to keep track of whether a model has been previously loaded or not so we can
+ // open the drawer on empty directories on first launch
+ private boolean mModelPreviousLoaded;
+
public FilesTuner(Context context, State state) {
super(context, state);
}
@@ -230,10 +234,12 @@
@Override
void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
// When launched into empty root, open drawer.
- if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch) {
+ if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch
+ && !mModelPreviousLoaded) {
// This noops on layouts without drawer, so no need to guard.
((BaseActivity) mContext).setRootsDrawerOpen(true);
}
+ mModelPreviousLoaded = true;
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
index 3642b01..e2a28ad9a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -37,6 +37,7 @@
import com.android.documentsui.model.DocumentInfo;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -403,11 +404,18 @@
public @Nullable Cursor getItem(String modelId) {
Integer pos = mPositions.get(modelId);
- if (pos != null) {
- mCursor.moveToPosition(pos);
- return mCursor;
+ if (pos == null) {
+ if (DEBUG) Log.d(TAG, "Unabled to find cursor position for modelId: " + modelId);
+ return null;
}
- return null;
+
+ if (!mCursor.moveToPosition(pos)) {
+ if (DEBUG) Log.d(TAG,
+ "Unabled to move cursor to position " + pos + " for modelId: " + modelId);
+ return null;
+ }
+
+ return mCursor;
}
boolean isEmpty() {
@@ -424,8 +432,11 @@
final List<DocumentInfo> docs = new ArrayList<>(size);
for (String modelId: items.getAll()) {
final Cursor cursor = getItem(modelId);
- assert(cursor != null);
-
+ if (cursor == null) {
+ Log.w(TAG,
+ "Skipping document. Unabled to obtain cursor for modelId: " + modelId);
+ continue;
+ }
docs.add(DocumentInfo.fromDirectoryCursor(cursor));
}
return docs;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index 1285b34..35d8988 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -378,8 +378,8 @@
* @param pos The anchor position for the selection range.
*/
void startRangeSelection(int pos) {
- attemptSelect(mAdapter.getModelId(pos));
- setSelectionRangeBegin(pos);
+ attemptSelect(mAdapter.getModelId(pos));
+ setSelectionRangeBegin(pos);
}
/**
@@ -1268,6 +1268,11 @@
notifySelectionChanged();
}
+ @Override
+ public boolean onBeforeItemStateChange(String id, boolean nextState) {
+ return notifyBeforeItemStateChange(id, nextState);
+ }
+
private class ViewScroller implements Runnable {
/**
* The number of milliseconds of scrolling at which scroll speed continues to increase.
@@ -1655,7 +1660,9 @@
if (id != null) {
// The adapter inserts items for UI layout purposes that aren't associated
// with files. Those will have a null model ID. Don't select them.
- mSelection.add(id);
+ if (canSelect(id)) {
+ mSelection.add(id);
+ }
}
if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
row, rowStartIndex, rowEndIndex)) {
@@ -1669,6 +1676,21 @@
}
/**
+ * @return True if the item is selectable.
+ */
+ private boolean canSelect(String id) {
+ // TODO: Simplify the logic, so the check whether we can select is done in one place.
+ // Consider injecting FragmentTuner, or move the checks from MultiSelectManager to
+ // Selection.
+ for (OnSelectionChangedListener listener : mOnSelectionChangedListeners) {
+ if (!listener.onBeforeItemStateChange(id, true)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* @return Returns true if the position is the nearest to the origin, or, in the case of the
* lower-right corner, whether it is possible that the position is the nearest to the
* origin. See comment below for reasoning for this special case.
@@ -1700,6 +1722,7 @@
*/
static interface OnSelectionChangedListener {
public void onSelectionChanged(Set<String> updatedSelection);
+ public boolean onBeforeItemStateChange(String id, boolean nextState);
}
void addOnSelectionChangedListener(OnSelectionChangedListener listener) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 31ce837..3a86a51 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -139,11 +139,13 @@
};
public static DocumentInfo fromDirectoryCursor(Cursor cursor) {
+ assert(cursor != null);
final String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
return fromCursor(cursor, authority);
}
public static DocumentInfo fromCursor(Cursor cursor, String authority) {
+ assert(cursor != null);
final DocumentInfo info = new DocumentInfo();
info.updateFromCursor(cursor, authority);
return info;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 0709652..d54bdfd 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -334,15 +334,6 @@
}
}
- public Drawable loadToolbarIcon(Context context) {
- if (derivedIcon != 0) {
- return IconUtils.applyTintAttr(context, derivedIcon,
- android.R.attr.colorControlNormal);
- } else {
- return IconUtils.loadPackageIcon(context, authority, icon);
- }
- }
-
@Override
public boolean equals(Object o) {
if (o == null) {
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
index 0c0e0b7..cc119fe 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
@@ -76,6 +76,11 @@
public void onSelectionChanged(Set<String> updatedSelection) {
lastSelection = updatedSelection;
}
+
+ @Override
+ public boolean onBeforeItemStateChange(String id, boolean nextState) {
+ return true;
+ }
});
}
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 61966b2..09fec81 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -334,6 +334,14 @@
<!-- An explanation text that the password needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
<string name="kg_prompt_reason_switch_profiles_password">Password required when you switch profiles</string>
+ <!-- An explanation text that the credential needs to be entered because a device admin has
+ locked the device. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_device_admin">Device administrator locked device</string>
+
+ <!-- An explanation text that the credential needs to be entered because the user has clicked
+ the force lock button. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_user_request">Device was locked manually</string>
+
<!-- An explanation text that the pattern needs to be solved since it hasn't been solved in a while. [CHAR LIMIT=80]-->
<plurals name="kg_prompt_reason_time_pattern">
<item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm pattern.</item>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
index 63dec8b..189f5b7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -117,6 +117,10 @@
return R.string.kg_prompt_reason_restart_password;
case PROMPT_REASON_TIMEOUT:
return R.string.kg_prompt_reason_timeout_password;
+ case PROMPT_REASON_DEVICE_ADMIN:
+ return R.string.kg_prompt_reason_device_admin;
+ case PROMPT_REASON_USER_REQUEST:
+ return R.string.kg_prompt_reason_user_request;
case PROMPT_REASON_NONE:
return 0;
default:
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index be2701d..e070492 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -339,6 +339,14 @@
mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern,
true /* important */);
break;
+ case PROMPT_REASON_DEVICE_ADMIN:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_device_admin,
+ true /* important */);
+ break;
+ case PROMPT_REASON_USER_REQUEST:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_user_request,
+ true /* important */);
+ break;
case PROMPT_REASON_NONE:
break;
default:
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index fe98cb8..f14290a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -108,6 +108,10 @@
return R.string.kg_prompt_reason_restart_pin;
case PROMPT_REASON_TIMEOUT:
return R.string.kg_prompt_reason_timeout_pin;
+ case PROMPT_REASON_DEVICE_ADMIN:
+ return R.string.kg_prompt_reason_device_admin;
+ case PROMPT_REASON_USER_REQUEST:
+ return R.string.kg_prompt_reason_user_request;
case PROMPT_REASON_NONE:
return 0;
default:
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 00d31a7..90dd440 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -16,6 +16,7 @@
package com.android.mtp;
+import android.annotation.Nullable;
import android.content.Context;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
@@ -27,6 +28,7 @@
import android.mtp.MtpDeviceInfo;
import android.mtp.MtpEvent;
import android.mtp.MtpObjectInfo;
+import android.mtp.MtpStorageInfo;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -80,9 +82,7 @@
}
}
- if (rawDevice == null) {
- throw new IOException("Not found USB device: " + deviceId);
- }
+ ensureNotNull(rawDevice, "Not found USB device: " + deviceId);
if (!mManager.hasPermission(rawDevice)) {
mManager.grantPermission(rawDevice);
@@ -93,10 +93,9 @@
final MtpDevice device = new MtpDevice(rawDevice);
- final UsbDeviceConnection connection = mManager.openDevice(rawDevice);
- if (connection == null) {
- throw new IOException("Failed to open a USB connection.");
- }
+ final UsbDeviceConnection connection = ensureNotNull(
+ mManager.openDevice(rawDevice),
+ "Failed to open a USB connection.");
if (!device.open(connection)) {
// We cannot open connection when another application use the device.
@@ -104,13 +103,11 @@
}
// Handle devices that fail to obtain storages just after opening a MTP session.
- final int[] storageIds = device.getStorageIds();
- if (storageIds == null) {
- throw new IOException("Not found MTP storages in the device.");
- }
+ final int[] storageIds = ensureNotNull(
+ device.getStorageIds(),
+ "Not found MTP storages in the device.");
mDevices.put(deviceId, device);
-
return createDeviceRecord(rawDevice);
}
@@ -133,11 +130,9 @@
MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
synchronized (device) {
- final MtpObjectInfo info = device.getObjectInfo(objectHandle);
- if (info == null) {
- throw new IOException("Failed to get object info: " + objectHandle);
- }
- return info;
+ return ensureNotNull(
+ device.getObjectInfo(objectHandle),
+ "Failed to get object info: " + objectHandle);
}
}
@@ -145,12 +140,9 @@
throws IOException {
final MtpDevice device = getDevice(deviceId);
synchronized (device) {
- final int[] handles =
- device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle);
- if (handles == null) {
- throw new IOException("Failed to fetch object handles.");
- }
- return handles;
+ return ensureNotNull(
+ device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle),
+ "Failed to fetch object handles.");
}
}
@@ -158,7 +150,9 @@
throws IOException {
final MtpDevice device = getDevice(deviceId);
synchronized (device) {
- return device.getObject(objectHandle, expectedSize);
+ return ensureNotNull(
+ device.getObject(objectHandle, expectedSize),
+ "Failed to fetch object bytes");
}
}
@@ -181,7 +175,9 @@
byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
synchronized (device) {
- return device.getThumbnail(objectHandle);
+ return ensureNotNull(
+ device.getThumbnail(objectHandle),
+ "Failed to obtain thumbnail bytes");
}
}
@@ -216,7 +212,7 @@
final MtpDevice device = getDevice(deviceId);
synchronized (device) {
final int result = (int) device.getParent(objectHandle);
- if (result < 0) {
+ if (result == 0xffffffff) {
throw new FileNotFoundException("Not found parent object");
}
return result;
@@ -227,7 +223,9 @@
throws IOException {
final MtpDevice device = getDevice(deviceId);
synchronized (device) {
- device.importFile(objectHandle, target);
+ if (!device.importFile(objectHandle, target)) {
+ throw new IOException("Failed to import file to FD");
+ }
}
}
@@ -243,26 +241,25 @@
}
private synchronized MtpDevice getDevice(int deviceId) throws IOException {
- final MtpDevice device = mDevices.get(deviceId);
- if (device == null) {
- throw new IOException("USB device " + deviceId + " is not opened.");
- }
- return device;
+ return ensureNotNull(
+ mDevices.get(deviceId),
+ "USB device " + deviceId + " is not opened.");
}
private MtpRoot[] getRoots(int deviceId) throws IOException {
final MtpDevice device = getDevice(deviceId);
synchronized (device) {
- final int[] storageIds = device.getStorageIds();
- if (storageIds == null) {
- throw new IOException("Failed to obtain storage IDs.");
- }
- final MtpRoot[] results = new MtpRoot[storageIds.length];
+ final int[] storageIds =
+ ensureNotNull(device.getStorageIds(), "Failed to obtain storage IDs.");
+ final ArrayList<MtpRoot> roots = new ArrayList<>();
for (int i = 0; i < storageIds.length; i++) {
- results[i] = new MtpRoot(
- device.getDeviceId(), device.getStorageInfo(storageIds[i]));
+ final MtpStorageInfo info = device.getStorageInfo(storageIds[i]);
+ if (info == null) {
+ continue;
+ }
+ roots.add(new MtpRoot(device.getDeviceId(), info));
}
- return results;
+ return roots.toArray(new MtpRoot[roots.size()]);
}
}
@@ -313,4 +310,12 @@
}
return false;
}
+
+ private static <T> T ensureNotNull(@Nullable T t, String errorMessage) throws IOException {
+ if (t != null) {
+ return t;
+ } else {
+ throw new IOException(errorMessage);
+ }
+ }
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index e7aebdd..c411186 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -320,6 +320,8 @@
mFileProvider, new RemotePrintDocument.RemoteAdapterDeathObserver() {
@Override
public void onDied() {
+ Log.w(LOG_TAG, "Printing app died unexpectedly");
+
// If we are finishing or we are in a state that we do not need any
// data from the printing app, then no need to finish.
if (isFinishing() || (isFinalState(mState) && !mPrintedDocument.isUpdating())) {
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 084acac..985fe3c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -804,7 +804,7 @@
<string name="disabled_by_admin">Disabled by administrator</string>
<!-- Option in navigation drawer that leads to Settings main screen [CHAR LIMIT=30] -->
- <string name="home">Home</string>
+ <string name="home">Settings Home</string>
<string-array name="battery_labels" translatable="false">
<item>0%</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 8881034..8c2af45 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -839,8 +839,18 @@
for (int i = 0; i < mEntriesMap.size(); i++) {
int userId = mEntriesMap.keyAt(i);
- List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(launchIntent,
- PackageManager.GET_DISABLED_COMPONENTS, userId);
+ // If we do not specify MATCH_DIRECT_BOOT_AWARE or
+ // MATCH_DIRECT_BOOT_UNAWARE, system will derive and update the flags
+ // according to the user's lock state. When the user is locked, components
+ // with ComponentInfo#directBootAware == false will be filtered. We should
+ // explicitly include both direct boot aware and unaware components here.
+ List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
+ launchIntent,
+ PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ userId
+ );
synchronized (mEntriesMap) {
if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_LAUNCHER acquired lock");
HashMap<String, AppEntry> userEntries = mEntriesMap.valueAt(i);
@@ -1116,6 +1126,10 @@
public boolean mounted;
+ /**
+ * Setting this to {@code true} prevents the entry to be filtered by
+ * {@link #FILTER_DOWNLOADED_AND_LAUNCHER}.
+ */
public boolean hasLauncherEntry;
public String getNormalizedLabel() {
@@ -1286,6 +1300,9 @@
}
};
+ /**
+ * Displays a combined list with "downloaded" and "visible in launcher" apps only.
+ */
public static final AppFilter FILTER_DOWNLOADED_AND_LAUNCHER = new AppFilter() {
public void init() {
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 640399f..8dc247a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1324,6 +1324,9 @@
}
private static void appendSettingToCursor(MatrixCursor cursor, Setting setting) {
+ if (setting == null) {
+ return;
+ }
final int columnCount = cursor.getColumnCount();
String[] values = new String[columnCount];
diff --git a/packages/Shell/res/layout/confirm_repeat.xml b/packages/Shell/res/layout/confirm_repeat.xml
index d12f467..ad90af1 100644
--- a/packages/Shell/res/layout/confirm_repeat.xml
+++ b/packages/Shell/res/layout/confirm_repeat.xml
@@ -38,5 +38,5 @@
android:id="@android:id/checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/bugreport_confirm_repeat" />
+ android:text="@string/bugreport_confirm_dont_repeat" />
</LinearLayout>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index 5d90189..95e36fd 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -20,8 +20,6 @@
<string name="bugreport_in_progress_title">Bug report <xliff:g id="id">#%d</xliff:g> is being generated</string>
<!-- Title of notification indicating a bugreport has been successfully captured. [CHAR LIMIT=50] -->
<string name="bugreport_finished_title">Bug report <xliff:g id="id">#%d</xliff:g> captured</string>
- <!-- Title of notification indicating a bugreport has been successfully captured, but screenshot is not finished yet. [CHAR LIMIT=50] -->
- <string name="bugreport_finished_pending_screenshot_title">Bug report <xliff:g id="id">#%d</xliff:g> captured but screenshot pending</string>
<!-- Title of notification indicating a bugreport is being updated before it can be shared. [CHAR LIMIT=50] -->
<string name="bugreport_updating_title">Adding details to the bug report</string>
<!-- Content notification indicating a bugreport is being updated before it can be shared, asking the user to wait [CHAR LIMIT=50] -->
@@ -37,9 +35,9 @@
<string name="bugreport_finished_pending_screenshot_text" product="default">Tap to share your bug report without a screenshot or wait for the screenshot to finish</string>
<!-- Body of dialog informing user about contents of a bugreport. [CHAR LIMIT=NONE] -->
- <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people you trust.</string>
- <!-- Checkbox that indicates this dialog should be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
- <string name="bugreport_confirm_repeat">Show this message next time</string>
+ <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, which may include data you consider sensitive (such as app-usage and location data). Only share bug reports with people and apps you trust.</string>
+ <!-- Checkbox that indicates this dialog should not be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
+ <string name="bugreport_confirm_dont_repeat">Don\'t show again</string>
<!-- Title for documents backend that offers bugreports. -->
<string name="bugreport_storage_title">Bug reports</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportPrefs.java b/packages/Shell/src/com/android/shell/BugreportPrefs.java
index 3748e89..93690d4 100644
--- a/packages/Shell/src/com/android/shell/BugreportPrefs.java
+++ b/packages/Shell/src/com/android/shell/BugreportPrefs.java
@@ -22,22 +22,24 @@
/**
* Preferences related to bug reports.
*/
-public class BugreportPrefs {
- private static final String PREFS_BUGREPORT = "bugreports";
+final class BugreportPrefs {
+ static final String PREFS_BUGREPORT = "bugreports";
private static final String KEY_WARNING_STATE = "warning-state";
- public static final int STATE_UNKNOWN = 0;
- public static final int STATE_SHOW = 1;
- public static final int STATE_HIDE = 2;
+ static final int STATE_UNKNOWN = 0;
+ // Shows the warning dialog.
+ static final int STATE_SHOW = 1;
+ // Skips the warning dialog.
+ static final int STATE_HIDE = 2;
- public static int getWarningState(Context context, int def) {
+ static int getWarningState(Context context, int def) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFS_BUGREPORT, Context.MODE_PRIVATE);
return prefs.getInt(KEY_WARNING_STATE, def);
}
- public static void setWarningState(Context context, int value) {
+ static void setWarningState(Context context, int value) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFS_BUGREPORT, Context.MODE_PRIVATE);
prefs.edit().putInt(KEY_WARNING_STATE, value).apply();
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 796dff5..502eed1 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -17,7 +17,8 @@
package com.android.shell;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
-import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.STATE_HIDE;
+import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
import static com.android.shell.BugreportPrefs.getWarningState;
import java.io.BufferedOutputStream;
@@ -927,7 +928,7 @@
final Intent notifIntent;
// Send through warning dialog by default
- if (getWarningState(mContext, STATE_SHOW) == STATE_SHOW) {
+ if (getWarningState(mContext, STATE_UNKNOWN) != STATE_HIDE) {
notifIntent = buildWarningIntent(mContext, sendIntent);
} else {
notifIntent = sendIntent;
@@ -956,15 +957,10 @@
shareIntent.putExtra(EXTRA_ID, info.id);
shareIntent.putExtra(EXTRA_INFO, info);
- final String title, content;
- if (takingScreenshot) {
- title = context.getString(R.string.bugreport_finished_pending_screenshot_title,
- info.id);
- content = context.getString(R.string.bugreport_finished_pending_screenshot_text);
- } else {
- title = context.getString(R.string.bugreport_finished_title, info.id);
- content = context.getString(R.string.bugreport_finished_text);
- }
+ final String title = context.getString(R.string.bugreport_finished_title, info.id);
+ final String content = takingScreenshot ?
+ context.getString(R.string.bugreport_finished_pending_screenshot_text)
+ : context.getString(R.string.bugreport_finished_text);
final Notification.Builder builder = newBaseNotification(context)
.setContentTitle(title)
.setTicker(title)
diff --git a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
index a1d879a..da33a65 100644
--- a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
+++ b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
@@ -59,7 +59,7 @@
ap.mNegativeButtonListener = this;
mConfirmRepeat = (CheckBox) ap.mView.findViewById(android.R.id.checkbox);
- mConfirmRepeat.setChecked(getWarningState(this, STATE_UNKNOWN) == STATE_SHOW);
+ mConfirmRepeat.setChecked(getWarningState(this, STATE_UNKNOWN) != STATE_SHOW);
setupAlert();
}
@@ -68,7 +68,7 @@
public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) {
// Remember confirm state, and launch target
- setWarningState(this, mConfirmRepeat.isChecked() ? STATE_SHOW : STATE_HIDE);
+ setWarningState(this, mConfirmRepeat.isChecked() ? STATE_HIDE : STATE_SHOW);
startActivity(mSendIntent);
}
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 3b53055..537e4c5 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -17,7 +17,14 @@
package com.android.shell;
import static android.test.MoreAsserts.assertContainsRegex;
+
import static com.android.shell.ActionSendMultipleConsumerActivity.UI_NAME;
+import static com.android.shell.BugreportPrefs.PREFS_BUGREPORT;
+import static com.android.shell.BugreportPrefs.STATE_HIDE;
+import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
+import static com.android.shell.BugreportPrefs.getWarningState;
+import static com.android.shell.BugreportPrefs.setWarningState;
import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
import static com.android.shell.BugreportProgressService.EXTRA_ID;
import static com.android.shell.BugreportProgressService.EXTRA_MAX;
@@ -48,12 +55,12 @@
import java.util.zip.ZipOutputStream;
import libcore.io.Streams;
+
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.Instrumentation;
import android.app.NotificationManager;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -62,7 +69,6 @@
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.text.TextUtils;
@@ -70,7 +76,6 @@
import android.util.Log;
import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
-import com.android.shell.BugreportProgressService;
/**
* Integration tests for {@link BugreportReceiver}.
@@ -131,9 +136,6 @@
private static final boolean RENAMED_SCREENSHOTS = true;
private static final boolean DIDNT_RENAME_SCREENSHOTS = false;
- private static final boolean PENDING_SCREENSHOT = true;
- private static final boolean NOT_PENDING_SCREENSHOT = false;
-
private String mDescription;
private String mPlainTextPath;
@@ -171,7 +173,7 @@
}
mDescription = sb.toString();
- BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_HIDE);
+ setWarningState(mContext, STATE_HIDE);
}
public void testProgress() throws Exception {
@@ -432,7 +434,7 @@
sendBugreportStarted(ID2, PID2, NAME2, 1000);
sendBugreportFinished(ID, mZipPath, mScreenshotPath);
- Bundle extras = acceptBugreportAndGetSharedIntent(ID, PENDING_SCREENSHOT);
+ Bundle extras = acceptBugreportAndGetSharedIntent(ID);
detailsUi = new DetailsUi(mUiBot, ID2);
detailsUi.assertName(NAME2);
@@ -503,9 +505,29 @@
assertServiceNotRunning();
}
- public void testBugreportFinished_withWarning() throws Exception {
- // Explicitly shows the warning.
- BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
+ public void testBugreportFinished_withWarningFirstTime() throws Exception {
+ bugreportFinishedWithWarningTest(null);
+ }
+
+ public void testBugreportFinished_withWarningUnknownState() throws Exception {
+ bugreportFinishedWithWarningTest(STATE_UNKNOWN);
+ }
+
+ public void testBugreportFinished_withWarningShowAgain() throws Exception {
+ bugreportFinishedWithWarningTest(STATE_SHOW);
+ }
+
+ private void bugreportFinishedWithWarningTest(Integer propertyState) throws Exception {
+ if (propertyState == null) {
+ // Clear properties
+ mContext.getSharedPreferences(PREFS_BUGREPORT, Context.MODE_PRIVATE)
+ .edit().clear().commit();
+ // Sanity check...
+ assertEquals("Did not reset properties", STATE_UNKNOWN,
+ getWarningState(mContext, STATE_UNKNOWN));
+ } else {
+ setWarningState(mContext, propertyState);
+ }
// Send notification and click on share.
sendBugreportFinished(NO_ID, mPlainTextPath, null);
@@ -513,10 +535,16 @@
// Handle the warning
mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
- // TODO: get ok and showMessageAgain from the dialog reference above
- UiObject showMessageAgain =
- mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_repeat));
- mUiBot.click(showMessageAgain, "show-message-again");
+ // TODO: get ok and dontShowAgain from the dialog reference above
+ UiObject dontShowAgain =
+ mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_dont_repeat));
+ final boolean firstTime = propertyState == null || propertyState == STATE_UNKNOWN;
+ if (firstTime) {
+ assertTrue("Checkbox should be checked by default", dontShowAgain.isChecked());
+ } else {
+ assertFalse("Checkbox should not be checked", dontShowAgain.isChecked());
+ mUiBot.click(dontShowAgain, "dont-show-again");
+ }
UiObject ok = mUiBot.getVisibleObject(mContext.getString(com.android.internal.R.string.ok));
mUiBot.click(ok, "ok");
@@ -526,8 +554,8 @@
assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
// Make sure it's hidden now.
- int newState = BugreportPrefs.getWarningState(mContext, BugreportPrefs.STATE_UNKNOWN);
- assertEquals("Didn't change state", BugreportPrefs.STATE_HIDE, newState);
+ int newState = getWarningState(mContext, STATE_UNKNOWN);
+ assertEquals("Didn't change state", STATE_HIDE, newState);
}
public void testShareBugreportAfterServiceDies() throws Exception {
@@ -623,7 +651,7 @@
private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath,
String screenshotPath) {
sendBugreportFinished(id, bugreportPath, screenshotPath);
- return acceptBugreportAndGetSharedIntent(id, NOT_PENDING_SCREENSHOT);
+ return acceptBugreportAndGetSharedIntent(id);
}
/**
@@ -632,11 +660,7 @@
* @return extras sent in the shared intent.
*/
private Bundle acceptBugreportAndGetSharedIntent(int id) {
- return acceptBugreportAndGetSharedIntent(id, NOT_PENDING_SCREENSHOT);
- }
-
- private Bundle acceptBugreportAndGetSharedIntent(int id, boolean pendingScreenshot) {
- acceptBugreport(id, pendingScreenshot);
+ acceptBugreport(id);
mUiBot.chooseActivity(UI_NAME);
return mListener.getExtras();
}
@@ -652,13 +676,7 @@
* Accepts the notification to share the finished bugreport.
*/
private void acceptBugreport(int id) {
- acceptBugreport(id, NOT_PENDING_SCREENSHOT);
- }
-
- private void acceptBugreport(int id, boolean pendingScreenshot) {
- final int res = pendingScreenshot ? R.string.bugreport_finished_pending_screenshot_title
- : R.string.bugreport_finished_title;
- mUiBot.clickOnNotification(mContext.getString(res, id));
+ mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, id));
}
/**
@@ -889,8 +907,8 @@
}
private String getPath(String file) {
- File rootDir = new ContextWrapper(mContext).getFilesDir();
- File dir = new File(rootDir, BUGREPORTS_DIR);
+ final File rootDir = mContext.getFilesDir();
+ final File dir = new File(rootDir, BUGREPORTS_DIR);
if (!dir.exists()) {
Log.i(TAG, "Creating directory " + dir);
assertTrue("Could not create directory " + dir, dir.mkdir());
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index bd3c6ba..c248adf 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -238,6 +238,19 @@
android:value="com.android.settings.category.system" />
</activity>
+ <activity-alias android:name=".DemoMode"
+ android:targetActivity=".tuner.TunerActivity"
+ android:icon="@drawable/tuner"
+ android:theme="@style/TunerSettings"
+ android:label="@string/demo_mode"
+ android:process=":tuner"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.settings.action.DEMO_MODE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity-alias>
+
<!-- Service used by secondary users to register themselves with the system user. -->
<service android:name=".recents.RecentsSystemUserService"
android:exported="false"
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_gain_animation.xml
similarity index 92%
rename from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
rename to packages/SystemUI/res/anim/tv_pip_controls_text_focus_gain_animation.xml
index 681ff91..257bf35 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_gain_animation.xml
@@ -18,4 +18,4 @@
android:propertyName="alpha"
android:valueTo="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_lose_animation.xml
similarity index 92%
rename from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
rename to packages/SystemUI/res/anim/tv_pip_controls_text_focus_lose_animation.xml
index e6deb0f..e032008 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_lose_animation.xml
@@ -18,4 +18,4 @@
android:propertyName="alpha"
android:valueTo="0"
android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
similarity index 92%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
copy to packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
index 681ff91..257bf35 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
@@ -18,4 +18,4 @@
android:propertyName="alpha"
android:valueTo="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
similarity index 92%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
copy to packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
index e6deb0f..e032008 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
@@ -18,4 +18,4 @@
android:propertyName="alpha"
android:valueTo="0"
android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ android:duration="100" />
diff --git a/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml b/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
index e98d43f..1e52a91 100644
--- a/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
+++ b/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
@@ -16,7 +16,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
- android:startColor="#99000000"
- android:endColor="#E6000000"
+ android:startColor="#4C000000"
+ android:endColor="#72000000"
android:angle="90"/>
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
index 405ea0c..0db1a57 100644
--- a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
@@ -14,11 +14,5 @@
limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <size
- android:width="34dp"
- android:height="34dp" />
- <solid
- android:color="#4DFFFFFF" />
-</shape>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="#9AFFFFFF" android:radius="17dp" />
diff --git a/packages/SystemUI/res/drawable/tv_pip_close_button.xml b/packages/SystemUI/res/drawable/tv_pip_close_button.xml
deleted file mode 100644
index 186a4ba..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_close_button.xml
+++ /dev/null
@@ -1,38 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:constantSize="true">
- <item android:state_focused="true">
- <layer-list>
- <item android:drawable="@drawable/tv_pip_button_focused" />
- <item android:drawable="@drawable/ic_close_white"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
- <item>
- <layer-list>
- <item android:drawable="@drawable/ic_close_white"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_full_button.xml b/packages/SystemUI/res/drawable/tv_pip_full_button.xml
deleted file mode 100644
index c48dc828..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_full_button.xml
+++ /dev/null
@@ -1,38 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:constantSize="true">
- <item android:state_focused="true">
- <layer-list>
- <item android:drawable="@drawable/tv_pip_button_focused" />
- <item android:drawable="@drawable/ic_fullscreen_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
- <item>
- <layer-list>
- <item android:drawable="@drawable/ic_fullscreen_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
index e247dec..2b58fc5 100644
--- a/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
@@ -16,8 +16,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <gradient
- android:startColor="#B2000000"
- android:endColor="#00000000"
- android:angle="90"/>
+ <stroke android:width="1dp" android:color="#33FFFFFF" />
</shape>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml
similarity index 61%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
copy to packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml
index 681ff91..e247dec 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+ 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.
@@ -13,9 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:propertyName="alpha"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ <gradient
+ android:startColor="#B2000000"
+ android:endColor="#00000000"
+ android:angle="90"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_pip_pause_button.xml b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
deleted file mode 100644
index bcc8973..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
+++ /dev/null
@@ -1,38 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:constantSize="true">
- <item android:state_focused="true">
- <layer-list>
- <item android:drawable="@drawable/tv_pip_button_focused" />
- <item android:drawable="@drawable/ic_pause_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
- <item>
- <layer-list>
- <item android:drawable="@drawable/ic_pause_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_play_button.xml b/packages/SystemUI/res/drawable/tv_pip_play_button.xml
deleted file mode 100644
index f77ea1d..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_play_button.xml
+++ /dev/null
@@ -1,38 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:constantSize="true">
- <item android:state_focused="true">
- <layer-list>
- <item android:drawable="@drawable/tv_pip_button_focused" />
- <item android:drawable="@drawable/ic_play_arrow_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
- <item>
- <layer-list>
- <item android:drawable="@drawable/ic_play_arrow_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
-</selector>
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout-television/recents_on_tv.xml
similarity index 94%
rename from packages/SystemUI/res/layout/recents_on_tv.xml
rename to packages/SystemUI/res/layout-television/recents_on_tv.xml
index 28ea66d..280fd20 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout-television/recents_on_tv.xml
@@ -19,7 +19,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
- android:clipToPadding="false">
+ android:clipToPadding="false"
+ android:background="@drawable/recents_tv_background_gradient">
<com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
android:id="@+id/task_list"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout-television/recents_tv_card_dismiss.xml b/packages/SystemUI/res/layout-television/recents_tv_card_dismiss.xml
new file mode 100644
index 0000000..186a058
--- /dev/null
+++ b/packages/SystemUI/res/layout-television/recents_tv_card_dismiss.xml
@@ -0,0 +1,43 @@
+<?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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/card_dismiss"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_gravity="center_horizontal"
+ android:alpha="0.0"
+ tools:showIn="@layout/recents_tv_task_card_view">
+ <ImageView
+ android:id="@+id/card_dismiss_icon"
+ android:layout_width="@dimen/recents_tv_dismiss_icon_size"
+ android:layout_height="@dimen/recents_tv_dismiss_icon_size"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="@dimen/recents_tv_dismiss_icon_top_margin"
+ android:layout_marginBottom="@dimen/recents_tv_dismiss_icon_bottom_margin"
+ android:src="@drawable/ic_cancel_white_24dp"/>
+ <TextView
+ android:id="@+id/card_dismiss_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/recents_tv_dismiss_text_size"
+ android:fontFamily="@string/font_roboto_light"
+ android:textColor="@color/recents_tv_dismiss_text_color"
+ android:text="@string/recents_tv_dismiss"
+ android:layout_gravity="center_horizontal"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-television/recents_tv_card_info_field.xml b/packages/SystemUI/res/layout-television/recents_tv_card_info_field.xml
new file mode 100644
index 0000000..20397c3
--- /dev/null
+++ b/packages/SystemUI/res/layout-television/recents_tv_card_info_field.xml
@@ -0,0 +1,47 @@
+<?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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/card_info_field"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:showIn="@layout/recents_tv_task_card_view_fallback_banner">
+ <ImageView
+ android:id="@+id/card_extra_badge"
+ android:layout_width="@dimen/recents_tv_card_extra_badge_size"
+ android:layout_height="@dimen/recents_tv_card_extra_badge_size"
+ android:layout_marginBottom="@dimen/recents_tv_icon_padding_bottom"
+ android:scaleType="fitCenter"
+ android:layout_centerVertical="true"
+ android:layout_alignParentEnd="true"/>
+ <TextView
+ android:id="@+id/card_title_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:includeFontPadding="true"
+ android:singleLine="true"
+ android:shadowColor="@color/recents_tv_text_shadow_color"
+ android:shadowRadius="5"
+ android:shadowDx="0"
+ android:shadowDy="0"
+ android:textColor="@color/recents_tv_card_title_text_color"
+ android:fontFamily="@string/font_roboto_regular"
+ android:textSize="@dimen/recents_tv_title_text_size"
+ android:paddingStart="@dimen/recents_tv_text_padding_start"
+ android:layout_marginBottom="@dimen/recents_tv_text_padding_bottom"
+ android:ellipsize="end"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml b/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml
new file mode 100644
index 0000000..9b89aa0
--- /dev/null
+++ b/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+<com.android.systemui.recents.tv.views.TaskCardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:layout_gravity="center"
+ android:layout_centerInParent="true"
+ android:clipToPadding="false"
+ android:orientation="vertical" >
+ <include layout="@layout/recents_tv_card_info_field"/>
+ <LinearLayout
+ android:id="@+id/card_view_thumbnail"
+ android:layout_width="@dimen/recents_tv_card_width"
+ android:layout_height="@dimen/recents_tv_screenshot_height"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:background="@color/recents_tv_card_background_color"
+ android:layout_centerHorizontal="true" >
+
+ <ImageView
+ android:id="@+id/card_view_banner_icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_centerHorizontal="true"
+ android:scaleType="centerCrop"
+ android:gravity="center" />
+
+ </LinearLayout>
+ <include layout="@layout/recents_tv_card_dismiss"/>
+</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/docked_stack_divider.xml b/packages/SystemUI/res/layout/docked_stack_divider.xml
index cfaf018..70e5451 100644
--- a/packages/SystemUI/res/layout/docked_stack_divider.xml
+++ b/packages/SystemUI/res/layout/docked_stack_divider.xml
@@ -24,6 +24,11 @@
android:id="@+id/docked_divider_background"
android:background="@color/docked_divider_background"/>
+ <com.android.systemui.stackdivider.MinimizedDockShadow
+ style="@style/DockedDividerMinimizedShadow"
+ android:id="@+id/minimized_dock_shadow"
+ android:alpha="0"/>">
+
<com.android.systemui.stackdivider.DividerHandleView
style="@style/DockedDividerHandle"
android:id="@+id/docked_divider_handle"
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 9dd3ad2..55d7fab 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -33,7 +33,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:gravity="center" />
+ android:gravity="center"
+ android:importantForAccessibility="yes"
+ android:focusable="true" />
<TextView
android:id="@android:id/edit"
diff --git a/packages/SystemUI/res/layout/recents_tv_task_card_view.xml b/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
deleted file mode 100644
index 766ef60..0000000
--- a/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
+++ /dev/null
@@ -1,97 +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.
--->
-<com.android.systemui.recents.tv.views.TaskCardView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:layout_gravity="center"
- android:layout_centerInParent="true"
- android:orientation="vertical"
- android:layoutDirection="ltr">
-
- <LinearLayout
- android:id="@+id/recents_tv_card"
- android:layout_width="@dimen/recents_tv_card_width"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:layout_gravity="center"
- android:orientation="vertical" >
- <LinearLayout
- android:id="@+id/card_info_field"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <ImageView
- android:id="@+id/card_extra_badge"
- android:layout_width="@dimen/recents_tv_card_extra_badge_size"
- android:layout_height="@dimen/recents_tv_card_extra_badge_size"
- android:layout_marginBottom="@dimen/recents_tv_icon_padding_bottom"
- android:layout_marginEnd="@dimen/recents_tv_icon_padding_end"
- android:scaleType="fitCenter"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true" />
- <TextView
- android:id="@+id/card_title_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="false"
- android:includeFontPadding="true"
- android:minLines="1"
- android:maxLines="1"
- android:textColor="@color/recents_tv_card_title_text_color"
- android:fontFamily="@string/font_roboto_regular"
- android:textSize="@dimen/recents_tv_title_text_size"
- android:layout_marginBottom="@dimen/recents_tv_text_padding_bottom"
- android:ellipsize="end"/>
- </LinearLayout>
- <ImageView
- android:id="@+id/card_view_thumbnail"
- android:layout_width="match_parent"
- android:layout_height="@dimen/recents_tv_screenshot_height"
- android:scaleType="centerCrop"
- android:gravity="center"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"
- android:layout_below="@id/card_title_text" />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/card_dismiss"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="center_horizontal"
- android:layout_below="@id/recents_tv_card"
- android:alpha="0.0">
- <ImageView
- android:id="@+id/card_dismiss_icon"
- android:layout_width="@dimen/recents_tv_dismiss_icon_size"
- android:layout_height="@dimen/recents_tv_dismiss_icon_size"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="@dimen/recents_tv_dismiss_icon_top_margin"
- android:layout_marginBottom="@dimen/recents_tv_dismiss_icon_bottom_margin"
- android:src="@drawable/ic_cancel_white_24dp" />
- <TextView
- android:id="@+id/card_dismiss_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="@dimen/recents_tv_dismiss_text_size"
- android:fontFamily="@string/font_roboto_light"
- android:textColor="@color/recents_tv_dismiss_text_color"
- android:text="@string/recents_tv_dismiss"
- android:layout_gravity="center_horizontal" />
- </LinearLayout>
-</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/tv_pip_control_button.xml b/packages/SystemUI/res/layout/tv_pip_control_button.xml
new file mode 100644
index 0000000..0beeda1
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_control_button.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<!-- Layout for {@link com.android.systemui.tv.pip.PipControlButtonView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <ImageView android:id="@+id/button"
+ android:layout_width="34dp"
+ android:layout_height="34dp"
+ android:padding="5dp"
+ android:focusable="true"
+ android:src="@drawable/ic_fullscreen_white_24dp"
+ android:background="@drawable/tv_pip_button_focused"
+ android:layerType="software" />
+
+ <TextView android:id="@+id/desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:text="@string/pip_fullscreen"
+ android:alpha="0"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE" />
+</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/packages/SystemUI/res/layout/tv_pip_controls.xml
index 563441f..0a2f320 100644
--- a/packages/SystemUI/res/layout/tv_pip_controls.xml
+++ b/packages/SystemUI/res/layout/tv_pip_controls.xml
@@ -20,77 +20,26 @@
<!-- Layout for {@link com.android.systemui.tv.pip.PipControlsView}. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <LinearLayout
+ <com.android.systemui.tv.pip.PipControlButtonView
+ android:id="@+id/full_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:gravity="center">
+ android:src="@drawable/ic_fullscreen_white_24dp"
+ android:text="@string/pip_fullscreen" />
- <ImageView android:id="@+id/full_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:src="@drawable/tv_pip_full_button" />
-
- <TextView android:id="@+id/full_desc"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dp"
- android:gravity="center"
- android:visibility="invisible"
- android:text="@string/pip_fullscreen"
- android:fontFamily="sans-serif"
- android:textSize="12sp"
- android:textColor="#EEEEEE" />
- </LinearLayout>
-
- <LinearLayout
+ <com.android.systemui.tv.pip.PipControlButtonView
+ android:id="@+id/close_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginStart="-50dp"
- android:orientation="vertical"
- android:gravity="center">
+ android:src="@drawable/ic_close_white"
+ android:text="@string/pip_close" />
- <ImageView android:id="@+id/close_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:src="@drawable/tv_pip_close_button" />
-
- <TextView android:id="@+id/close_desc"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dp"
- android:gravity="center"
- android:visibility="invisible"
- android:text="@string/pip_close"
- android:fontFamily="sans-serif"
- android:textSize="12sp"
- android:textColor="#EEEEEE" />
- </LinearLayout>
-
- <LinearLayout android:id="@+id/play_pause"
+ <com.android.systemui.tv.pip.PipControlButtonView
+ android:id="@+id/play_pause_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginStart="-50dp"
- android:orientation="vertical"
- android:gravity="center" >
-
- <ImageView android:id="@+id/play_pause_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:src="@drawable/tv_pip_pause_button" />
-
- <TextView android:id="@+id/play_pause_desc"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dp"
- android:gravity="center"
- android:visibility="invisible"
- android:text="@string/pip_pause"
- android:fontFamily="sans-serif"
- android:textSize="12sp"
- android:textColor="#EEEEEE" />
- </LinearLayout>
+ android:src="@drawable/ic_pause_white_24dp"
+ android:text="@string/pip_pause" />
</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index 2647a99..72a4929 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -29,5 +29,6 @@
<com.android.systemui.tv.pip.PipControlsView
android:id="@+id/pip_controls"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:alpha="0" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
index 64bf3b5..608680c 100644
--- a/packages/SystemUI/res/layout/tv_pip_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -19,7 +19,8 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:background="@drawable/tv_pip_overlay_background">
<TextView
android:id="@+id/guide_overlay"
@@ -33,7 +34,7 @@
android:textSize="14sp"
android:textColor="#EEEEEE"
android:fontFamily="sans-serif"
- android:background="@drawable/tv_pip_overlay_background"
+ android:background="@drawable/tv_pip_overlay_text_background"
android:lineSpacingMultiplier="1.465"
android:gravity="center"
android:maxLines="2"
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index b711faa..82cba58 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -31,4 +31,8 @@
<item name="android:layout_height">96dp</item>
</style>
+ <style name="DockedDividerMinimizedShadow">
+ <item name="android:layout_width">8dp</item>
+ <item name="android:layout_height">match_parent</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 18fc419..d26fb06 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -151,7 +151,9 @@
<color name="docked_divider_background">#ff000000</color>
<color name="docked_divider_handle">#ffffff</color>
- <drawable name="forced_resizable_background">#40000000</drawable>
+ <drawable name="forced_resizable_background">#59000000</drawable>
+ <color name="minimize_dock_shadow_start">#60000000</color>
+ <color name="minimize_dock_shadow_end">#00000000</color>
<color name="default_remote_input_background">@*android:color/notification_default_color</color>
<color name="remote_input_hint">#99ffffff</color>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index 4126d3c..3817da0 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -17,7 +17,8 @@
*/
-->
<resources>
- <color name="recents_tv_card_background_color">#FF37474F</color>
+ <color name="recents_tv_card_background_color">#FF263238</color>
<color name="recents_tv_card_title_text_color">#CCEEEEEE</color>
<color name="recents_tv_dismiss_text_color">#7FEEEEEE</color>
+ <color name="recents_tv_text_shadow_color">#7F000000</color>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index f536f86..367dd1d 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -21,11 +21,13 @@
<dimen name="recents_tv_card_width">240dip</dimen>
<dimen name="recents_tv_screenshot_height">135dip</dimen>
<dimen name="recents_tv_card_extra_badge_size">20dip</dimen>
- <dimen name="recents_tv_banner_width">114dip</dimen>
- <dimen name="recents_tv_banner_height">64dip</dimen>
+ <dimen name="recents_tv_banner_width">130dip</dimen>
+ <dimen name="recents_tv_banner_height">72dip</dimen>
+ <dimen name="recents_tv_fallback_icon_width">40dip</dimen>
+ <dimen name="recents_tv_fallback_icon_height">40dip</dimen>
<dimen name="recents_tv_banner_margin_top">16dip</dimen>
<dimen name="recents_tv_icon_padding_bottom">8dip</dimen>
- <dimen name="recents_tv_icon_padding_end">12dip</dimen>
+ <dimen name="recents_tv_text_padding_start">12dip</dimen>
<dimen name="recents_tv_text_padding_bottom">12dip</dimen>
<!-- Padding for grid view in recents view on tv -->
@@ -54,8 +56,6 @@
<!-- Extra space around the PIP and its outline in PIP onboarding activity -->
<dimen name="tv_pip_bounds_space">3dp</dimen>
- <!-- Extra space around the PIP control button icon to match with the focused circle -->
- <dimen name="tv_pip_button_icon_padding">5dp</dimen>
<!-- Values for entering Recents and exiting Recents -->
<dimen name="recents_tv_home_recents_shift">125dip</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index dc9ffa9..a4d7a18 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1595,4 +1595,7 @@
<!-- accessibility label for button to expand quick settings [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_expand">Expand quick settings.</string>
+ <!-- accessibility label for paging indicator in quick settings [CHAR LIMITi=NONE] -->
+ <string name="accessibility_quick_settings_page">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index f560a13..0730083 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -308,6 +308,11 @@
<item name="android:layout_gravity">center_vertical</item>
</style>
+ <style name="DockedDividerMinimizedShadow">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">8dp</item>
+ </style>
+
<style name="DockedDividerHandle">
<item name="android:layout_gravity">center_horizontal</item>
<item name="android:layout_width">96dp</item>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index a130cf9..1af9075 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -100,10 +100,12 @@
</PreferenceScreen>
+ <!--
<Preference
android:key="color_transform"
android:title="@string/color_and_appearance"
android:fragment="com.android.systemui.tuner.ColorAndAppearanceFragment" />
+ -->
<PreferenceScreen
android:key="volume_and_do_not_disturb"
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 087f61e..076b5bc 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -37,7 +37,7 @@
import com.android.systemui.statusbar.policy.BatteryController;
-public class BatteryMeterDrawable extends Drawable implements DemoMode,
+public class BatteryMeterDrawable extends Drawable implements
BatteryController.BatteryStateChangeCallback {
private static final float ASPECT_RATIO = 9.5f / 14.5f;
@@ -184,14 +184,12 @@
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
updateShowPercent();
- if (mDemoMode) return;
mBatteryController.addStateChangedCallback(this);
}
public void stopListening() {
mListening = false;
mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
- if (mDemoMode) return;
mBatteryController.removeStateChangedCallback(this);
}
@@ -507,35 +505,6 @@
return 0;
}
- private boolean mDemoMode;
-
- @Override
- public void dispatchDemoCommand(String command, Bundle args) {
- if (!mDemoMode && command.equals(COMMAND_ENTER)) {
- mBatteryController.removeStateChangedCallback(this);
- mDemoMode = true;
- if (mListening) {
- mBatteryController.removeStateChangedCallback(this);
- }
- } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
- mDemoMode = false;
- postInvalidate();
- if (mListening) {
- mBatteryController.addStateChangedCallback(this);
- }
- } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
- String level = args.getString("level");
- String plugged = args.getString("plugged");
- if (level != null) {
- mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100);
- }
- if (plugged != null) {
- mPluggedIn = Boolean.parseBoolean(plugged);
- }
- postInvalidate();
- }
- }
-
private final class SettingObserver extends ContentObserver {
public SettingObserver() {
super(new Handler());
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 001d1f2..73b9d02 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -32,7 +32,8 @@
/**
* Docks the top-most task and opens recents.
*/
- boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds);
+ boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds,
+ int metricsDockAction);
/**
* Called during a drag-from-navbar-in gesture.
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 455a69f..39a3412 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -63,7 +63,8 @@
* above.
*/
private final Class<?>[] SERVICES_PER_USER = new Class[] {
- com.android.systemui.recents.Recents.class
+ com.android.systemui.recents.Recents.class,
+ com.android.systemui.tv.pip.PipUI.class
};
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f892fd6..1abd073 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1477,12 +1477,14 @@
private void sendUserPresentBroadcast() {
synchronized (this) {
if (mBootCompleted) {
- final UserHandle currentUser = new UserHandle(KeyguardUpdateMonitor.getCurrentUser());
+ int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
+ final UserHandle currentUser = new UserHandle(currentUserId);
final UserManager um = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
for (int profileId : um.getProfileIdsWithDisabled(currentUser.getIdentifier())) {
mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, UserHandle.of(profileId));
}
+ getLockPatternUtils().userPresent(currentUserId);
} else {
mBootSendUserPresent = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 5cb46ac..e050b0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -60,6 +60,8 @@
public void setLocation(float location) {
int index = (int) location;
+ setContentDescription(getContext().getString(R.string.accessibility_quick_settings_page,
+ (index + 1), getChildCount()));
int position = index << 1 | ((location != index) ? 1 : 0);
if (DEBUG) Log.d(TAG, "setLocation " + location + " " + index + " " + position);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 4d959d8..af81c19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -87,6 +87,7 @@
public void setOnKeyguard(boolean onKeyguard) {
mOnKeyguard = onKeyguard;
+ mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE);
if (mOnKeyguard) {
clearAnimationState();
}
@@ -290,7 +291,7 @@
@Override
public void onAnimationStarted() {
- mQuickQsPanel.setVisibility(View.VISIBLE);
+ mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE);
if (mOnFirstPage) {
final int N = mTopFiveQs.size();
for (int i = 0; i < N; i++) {
@@ -302,12 +303,11 @@
private void clearAnimationState() {
final int N = mAllViews.size();
mQuickQsPanel.setAlpha(0);
- mQuickQsPanel.setVisibility(View.VISIBLE);
for (int i = 0; i < N; i++) {
View v = mAllViews.get(i);
v.setAlpha(1);
- v.setTranslationX(1);
- v.setTranslationY(1);
+ v.setTranslationX(0);
+ v.setTranslationY(0);
}
final int N2 = mTopFiveQs.size();
for (int i = 0; i < N2; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
index e3a4909..ef75562 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -70,8 +70,8 @@
super.onFinishInflate();
mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
mQSDetail = (QSDetail) findViewById(R.id.qs_detail);
- mQSDetail.setQsPanel(mQSPanel);
mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
+ mQSDetail.setQsPanel(mQSPanel, mHeader);
mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
mQSPanel);
mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 50c0cca..0cf7e479 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -35,6 +35,7 @@
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile.DetailAdapter;
+import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
import com.android.systemui.statusbar.phone.QSTileHost;
public class QSDetail extends LinearLayout {
@@ -62,6 +63,7 @@
private boolean mClosingDetail;
private boolean mFullyExpanded;
private View mQsDetailHeaderBack;
+ private BaseStatusBarHeader mHeader;
public QSDetail(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -107,8 +109,9 @@
mDetailDoneButton.setOnClickListener(doneListener);
}
- public void setQsPanel(QSPanel panel) {
+ public void setQsPanel(QSPanel panel, BaseStatusBarHeader header) {
mQsPanel = panel;
+ mHeader = header;
mQsPanel.setCallback(mQsPanelCallback);
}
@@ -195,6 +198,7 @@
mClosingDetail = true;
mDetailAdapter = null;
listener = mTeardownDetailWhenDone;
+ mHeader.setVisibility(View.VISIBLE);
mQsPanel.setGridContentVisibility(true);
mQsPanelCallback.onScanStateChanged(false);
}
@@ -273,6 +277,7 @@
// Only hide content if still in detail state.
if (mDetailAdapter != null) {
mQsPanel.setGridContentVisibility(false);
+ mHeader.setVisibility(View.INVISIBLE);
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index e8e17b1..8925d45 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -387,7 +387,7 @@
}
}
}
- if (mTiles.get(mTiles.size() - 1) == null) {
+ if (mTiles.size() - 1 == mTileDividerIndex) {
mTiles.remove(mTiles.size() - 1);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 82daaa6..b2d7b48 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
@@ -36,10 +37,13 @@
import android.provider.Settings;
import android.util.EventLog;
import android.util.Log;
+import android.util.MutableBoolean;
import android.view.Display;
import android.view.View;
import android.widget.Toast;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
@@ -78,6 +82,10 @@
private final static String ACTION_HIDE_RECENTS = "com.android.systemui.recents.ACTION_HIDE";
private final static String ACTION_TOGGLE_RECENTS = "com.android.systemui.recents.ACTION_TOGGLE";
+ private static final String COUNTER_WINDOW_SUPPORTED = "window_enter_supported";
+ private static final String COUNTER_WINDOW_UNSUPPORTED = "window_enter_unsupported";
+ private static final String COUNTER_WINDOW_INCOMPATIBLE = "window_enter_incompatible";
+
private static SystemServicesProxy sSystemServicesProxy;
private static RecentsDebugFlags sDebugFlags;
private static RecentsTaskLoader sTaskLoader;
@@ -393,7 +401,8 @@
}
@Override
- public boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds) {
+ public boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds,
+ int metricsDockAction) {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
if (!isUserSetup()) {
@@ -413,7 +422,12 @@
boolean screenPinningActive = ssp.isScreenPinningActive();
boolean isTopTaskHome = topTask != null && SystemServicesProxy.isHomeStack(topTask.stackId);
if (topTask != null && !isTopTaskHome && !screenPinningActive) {
+ logDockAttempt(mContext, topTask.topActivity, topTask.resizeMode);
if (topTask.isDockable) {
+ if (metricsDockAction != -1) {
+ MetricsLogger.action(mContext, metricsDockAction,
+ topTask.topActivity.flattenToShortString());
+ }
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
} else {
@@ -444,6 +458,26 @@
}
}
+ public static void logDockAttempt(Context ctx, ComponentName activity, int resizeMode) {
+ if (resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE) {
+ MetricsLogger.action(ctx, MetricsEvent.ACTION_WINDOW_DOCK_UNRESIZABLE,
+ activity.flattenToShortString());
+ }
+ MetricsLogger.count(ctx, getMetricsCounterForResizeMode(resizeMode), 1);
+ }
+
+ private static String getMetricsCounterForResizeMode(int resizeMode) {
+ switch (resizeMode) {
+ case ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE:
+ return COUNTER_WINDOW_UNSUPPORTED;
+ case ActivityInfo.RESIZE_MODE_RESIZEABLE:
+ case ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE:
+ return COUNTER_WINDOW_SUPPORTED;
+ default:
+ return COUNTER_WINDOW_INCOMPATIBLE;
+ }
+ }
+
@Override
public void onDraggingInRecents(float distanceFromTop) {
if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 6b476ee..df79669 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -66,6 +66,7 @@
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
import com.android.systemui.recents.events.ui.UserInteractionEvent;
+import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
@@ -752,6 +753,13 @@
mIgnoreAltTabRelease = true;
}
+ public final void onBusEvent(final DragEndEvent event) {
+ // Handle the case where we drop onto a dock region
+ if (event.dropTarget instanceof TaskStack.DockState) {
+ mScrimViews.animateScrimToCurrentNavBarState(false /* hasStackTasks */);
+ }
+ }
+
@Override
public boolean onPreDraw() {
mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index fda340d..6d32293 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -175,7 +175,11 @@
ssp.registerTaskStackListener(mTaskStackListener);
// Initialize the static configuration resources
- reloadHeaderBarLayout();
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ mDummyStackView = new TaskStackView(mContext);
+ mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
+ null, false);
+ reloadResources();
// When we start, preload the data associated with the previous recent tasks.
// We can use a new plan since the caches will be the same.
@@ -194,7 +198,9 @@
}
public void onConfigurationChanged() {
- reloadHeaderBarLayout();
+ reloadResources();
+ mDummyStackView.reloadOnConfigurationChange();
+ mHeaderBar.onConfigurationChanged();
}
/**
@@ -542,11 +548,10 @@
}
/**
- * Reloads all the layouts for the header bar transition.
+ * Reloads all the resources for the current configuration.
*/
- private void reloadHeaderBarLayout() {
+ private void reloadResources() {
Resources res = mContext.getResources();
- LayoutInflater inflater = LayoutInflater.from(mContext);
mStatusBarHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
@@ -561,9 +566,6 @@
R.dimen.recents_task_view_header_height_tablet_land,
R.dimen.recents_task_view_header_height,
R.dimen.recents_task_view_header_height_tablet_land);
- mDummyStackView = new TaskStackView(mContext);
- mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
- null, false);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 44f220b..4ecda54 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -25,6 +25,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
+import android.os.Trace;
import android.util.ArraySet;
import android.util.IntProperty;
import android.util.Property;
@@ -261,6 +262,14 @@
}
/**
+ * Adds a trace event for debugging.
+ */
+ public static void addTraceEvent(String event) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, event);
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+
+ /**
* Returns a lightweight dump of a rect.
*/
public static String dumpRect(Rect r) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 7aeff1f..af1628b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -206,7 +206,7 @@
Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
thumbnail, title, titleDescription, dismissDescription, appInfoDescription,
activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp,
- t.isDockable, t.bounds, t.taskDescription);
+ t.isDockable, t.bounds, t.taskDescription, t.resizeMode, t.topActivity);
allTasks.add(task);
affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 24eeaf2..68c46a9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
@@ -174,6 +175,15 @@
@ViewDebug.ExportedProperty(category="recents")
public boolean isDockable;
+ /**
+ * Resize mode. See {@link ActivityInfo#resizeMode}.
+ */
+ @ViewDebug.ExportedProperty(category="recents")
+ public int resizeMode;
+
+ @ViewDebug.ExportedProperty(category="recents")
+ public ComponentName topActivity;
+
private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
public Task() {
@@ -184,7 +194,8 @@
Bitmap thumbnail, String title, String titleDescription, String dismissDescription,
String appInfoDescription, int colorPrimary, int colorBackground,
boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp,
- boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription) {
+ boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription,
+ int resizeMode, ComponentName topActivity) {
boolean isInAffiliationGroup = (affiliationTaskId != key.id);
boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
this.key = key;
@@ -206,6 +217,8 @@
this.isStackTask = isStackTask;
this.isSystemApp = isSystemApp;
this.isDockable = isDockable;
+ this.resizeMode = resizeMode;
+ this.topActivity = topActivity;
}
/**
@@ -231,6 +244,8 @@
this.isStackTask = o.isStackTask;
this.isSystemApp = o.isSystemApp;
this.isDockable = o.isDockable;
+ this.resizeMode = o.resizeMode;
+ this.topActivity = o.topActivity;
}
/**
@@ -300,6 +315,15 @@
return key.id != affiliationTaskId;
}
+ /**
+ * Returns the top activity component.
+ */
+ public ComponentName getTopComponent() {
+ return topActivity != null
+ ? topActivity
+ : key.baseIntent.getComponent();
+ }
+
@Override
public boolean equals(Object o) {
// Check that the id matches
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 13e1a14..60a85df 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -55,6 +55,7 @@
import com.android.systemui.recents.tv.views.RecentsTvView;
import com.android.systemui.recents.tv.views.TaskStackHorizontalGridView;
import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
+import com.android.systemui.recents.views.AnimationProps;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.tv.pip.PipManager;
import com.android.systemui.tv.pip.PipRecentsOverlayManager;
@@ -246,7 +247,7 @@
dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
dismissEvent.addPostAnimationCallback(closeSystemWindows);
- if(mTaskStackHorizontalGridView.getChildCount() > 0) {
+ if(mTaskStackHorizontalGridView.getChildCount() > 0 && animateTaskViews) {
mHomeRecentsEnterExitAnimationHolder.startExitAnimation(dismissEvent);
} else {
closeSystemWindows.run();
@@ -343,6 +344,13 @@
} else {
mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
}
+ if(mTaskStackHorizontalGridView.getStack().getTaskCount() > 1 && !mLaunchedFromHome) {
+ // If there are 2 or more tasks, and we are not launching from home
+ // set the selected position to the 2nd task to allow for faster app switching
+ mTaskStackHorizontalGridView.setSelectedPosition(1);
+ } else {
+ mTaskStackHorizontalGridView.setSelectedPosition(0);
+ }
// If this is a new instance from a configuration change, then we have to manually trigger
// the enter animation state, or if recents was relaunched by AM, without going through
@@ -494,12 +502,10 @@
}
public final void onBusEvent(AllTaskViewsDismissedEvent event) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- if (ssp.hasDockedTask()) {
+ if (mPipManager.isPipShown()) {
mRecentsView.showEmptyView();
} else {
- // Just go straight home (no animation necessary because there are no more task views)
- dismissRecentsToHome(false /* animateTaskViews */);
+ dismissRecentsToHome(false);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
index fd31872..dc0d1f1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
@@ -75,7 +75,8 @@
if (useThumbnailTransition) {
// Try starting with a thumbnail transition
- ActivityOptions opts = getThumbnailTransitionActivityOptionsForTV(topTask);
+ ActivityOptions opts = getThumbnailTransitionActivityOptionsForTV(topTask,
+ stack.getTaskCount());
if (opts != null) {
startRecentsActivity(topTask, opts, false /* fromHome */, true /* fromThumbnail */);
} else {
@@ -118,8 +119,8 @@
* Creates the activity options for an app->recents transition on TV.
*/
private ActivityOptions getThumbnailTransitionActivityOptionsForTV(
- ActivityManager.RunningTaskInfo topTask) {
- Rect rect = TaskCardView.getStartingCardThumbnailRect(mContext);
+ ActivityManager.RunningTaskInfo topTask, int numTasks) {
+ Rect rect = TaskCardView.getStartingCardThumbnailRect(mContext, numTasks);
SystemServicesProxy ssp = Recents.getSystemServices();
ThumbnailData thumbnailData = ssp.getTaskThumbnail(topTask.id);
if (thumbnailData.thumbnail != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
index fbcfa97..ae8d800 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
@@ -18,6 +18,7 @@
import android.animation.Animator;
import android.content.res.Resources;
+import android.view.View;
import android.widget.LinearLayout;
import com.android.systemui.Interpolators;
import com.android.systemui.recents.tv.views.TaskCardView;
@@ -26,15 +27,16 @@
public class DismissAnimationsHolder {
private LinearLayout mDismissArea;
- private LinearLayout mTaskCardView;
+ private LinearLayout mInfoField;
+ private View mThumbnailView;
private int mCardYDelta;
private long mShortDuration;
private long mLongDuration;
public DismissAnimationsHolder(TaskCardView taskCardView) {
- mTaskCardView = (LinearLayout) taskCardView.findViewById(R.id.recents_tv_card);
+ mInfoField = (LinearLayout) taskCardView.findViewById(R.id.card_info_field);
mDismissArea = (LinearLayout) taskCardView.findViewById(R.id.card_dismiss);
-
+ mThumbnailView = taskCardView.findViewById(R.id.card_view_thumbnail);
Resources res = taskCardView.getResources();
mCardYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
mShortDuration = res.getInteger(R.integer.dismiss_short_duration);
@@ -47,7 +49,13 @@
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.alpha(1.0f);
- mTaskCardView.animate()
+ mInfoField.animate()
+ .setDuration(mShortDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .translationYBy(mCardYDelta)
+ .alpha(0.5f);
+
+ mThumbnailView.animate()
.setDuration(mShortDuration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.translationYBy(mCardYDelta)
@@ -60,7 +68,13 @@
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.alpha(0.0f);
- mTaskCardView.animate()
+ mInfoField.animate()
+ .setDuration(mShortDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .translationYBy(-mCardYDelta)
+ .alpha(1.0f);
+
+ mThumbnailView.animate()
.setDuration(mShortDuration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.translationYBy(-mCardYDelta)
@@ -73,11 +87,25 @@
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.alpha(0.0f);
- mTaskCardView.animate()
+ mInfoField.animate()
.setDuration(mLongDuration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.translationYBy(mCardYDelta)
.alpha(0.0f)
.setListener(listener);
+
+ mThumbnailView.animate()
+ .setDuration(mLongDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .translationYBy(mCardYDelta)
+ .alpha(0.0f);
+ }
+
+ public void reset() {
+ mInfoField.setAlpha(1.0f);
+ mInfoField.setTranslationY(0);
+ mInfoField.animate().setListener(null);
+ mThumbnailView.setAlpha(1.0f);
+ mThumbnailView.setTranslationY(0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
index 278de87..497a0a3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
@@ -46,7 +46,6 @@
for(int i = 0; i < mGridView.getChildCount(); i++) {
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
view.setTranslationX(-mTranslationX);
- view.setAlpha(0.0f);
view.animate()
.alpha(1.0f)
.translationX(0)
@@ -76,7 +75,7 @@
public void setEnterFromHomeStartingAnimationValues() {
for(int i = 0; i < mGridView.getChildCount(); i++) {
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
- view.setTranslationX(-mTranslationX);
+ view.setTranslationX(0);
view.setAlpha(0.0f);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
index 888561c..9edd5af 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -26,6 +26,7 @@
import android.view.animation.Interpolator;
import com.android.systemui.R;
+import com.android.systemui.recents.tv.views.TaskCardView;
public class ViewFocusAnimator implements View.OnFocusChangeListener {
private final float mUnselectedScale;
@@ -94,10 +95,13 @@
mTargetView.setScaleX(scale);
mTargetView.setScaleY(scale);
- mTargetView.setZ(z);
mTargetView.setPadding((int) spacing, mTargetView.getPaddingTop(),
(int) spacing, mTargetView.getPaddingBottom());
+
+ if (mTargetView instanceof TaskCardView) {
+ ((TaskCardView) mTargetView).getThumbnailView().setZ(z);
+ }
}
public float getFocusProgress() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
index fb1127e..5b94ebe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
@@ -16,7 +16,6 @@
package com.android.systemui.recents.tv.views;
import android.annotation.Nullable;
-import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Context;
import android.graphics.Bitmap;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
index 53fdf62..594f6bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
-import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
@@ -35,7 +34,6 @@
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
-import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent;
import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -250,8 +248,9 @@
public TaskStackHorizontalGridView setTaskStackViewAdapter(
TaskStackHorizontalViewAdapter taskStackViewAdapter) {
- if(mTaskStackHorizontalView != null) {
+ if (mTaskStackHorizontalView != null) {
mTaskStackHorizontalView.setAdapter(taskStackViewAdapter);
+ taskStackViewAdapter.setTaskStackHorizontalGridView(mTaskStackHorizontalView);
}
return mTaskStackHorizontalView;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
index 99d478b..a72a7e6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -17,10 +17,15 @@
import android.animation.Animator;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
import android.view.KeyEvent;
@@ -38,7 +43,8 @@
public class TaskCardView extends LinearLayout {
- private ImageView mThumbnailView;
+ private static final String TAG = "TaskCardView";
+ private View mThumbnailView;
private TextView mTitleTextView;
private ImageView mBadgeView;
private Task mTask;
@@ -58,26 +64,28 @@
public TaskCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mViewFocusAnimator = new ViewFocusAnimator(this);
mDismissState = false;
+ Configuration config = getResources().getConfiguration();
+ setLayoutDirection(config.getLayoutDirection());
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mThumbnailView = (ImageView) findViewById(R.id.card_view_thumbnail);
+ mThumbnailView = findViewById(R.id.card_view_thumbnail);
mTitleTextView = (TextView) findViewById(R.id.card_title_text);
mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
mDismissAnimationsHolder = new DismissAnimationsHolder(this);
View title = findViewById(R.id.card_info_field);
mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, title);
+ mViewFocusAnimator = new ViewFocusAnimator(this);
}
public void init(Task task) {
mTask = task;
- mThumbnailView.setImageBitmap(task.thumbnail);
mTitleTextView.setText(task.title);
mBadgeView.setImageDrawable(task.icon);
+ setThumbnailView();
}
public Task getTask() {
@@ -95,7 +103,38 @@
return r;
}
- public static Rect getStartingCardThumbnailRect(Context context) {
+ public static Rect getStartingCardThumbnailRect(Context context, int numberOfTasks) {
+ if(numberOfTasks > 1) {
+ return getStartingCardThumbnailRectForStartPosition(context);
+ } else {
+ return getStartingCardThumbnailRectForFocusedPosition(context);
+ }
+ }
+
+ private static Rect getStartingCardThumbnailRectForStartPosition(Context context) {
+ Resources res = context.getResources();
+
+ int width = res.getDimensionPixelOffset(R.dimen.recents_tv_card_width);
+ int totalSpacing = res.getDimensionPixelOffset(R.dimen.recents_tv_gird_card_spacing) * 2
+ + res.getDimensionPixelOffset(R.dimen.recents_tv_gird_focused_card_delta);
+ int height = res.getDimensionPixelOffset(R.dimen.recents_tv_screenshot_height);
+ int topMargin = res.getDimensionPixelOffset(R.dimen.recents_tv_gird_row_top_margin);
+ int headerHeight = res.getDimensionPixelOffset(R.dimen.recents_tv_card_extra_badge_size) +
+ res.getDimensionPixelOffset(R.dimen.recents_tv_icon_padding_bottom);
+
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ Display display = wm.getDefaultDisplay();
+ Point size = new Point();
+ display.getSize(size);
+ int screenWidth = size.x;
+
+ return new Rect(screenWidth / 2 + width / 2 + totalSpacing,
+ topMargin + headerHeight,
+ screenWidth / 2 + width / 2 + totalSpacing + width,
+ topMargin + headerHeight + height);
+ }
+
+ private static Rect getStartingCardThumbnailRectForFocusedPosition(Context context) {
Resources res = context.getResources();
TypedValue out = new TypedValue();
@@ -127,7 +166,6 @@
Point size = new Point();
display.getSize(size);
int screenWidth = size.x;
- int screenHeight = size.y;
return new Rect(screenWidth / 2 - width / 2 - widthDelta / 2,
topMargin - totalHeightDelta / 2 + (int) (headerHeight * scale),
@@ -189,6 +227,7 @@
}
public void startDismissTaskAnimation(Animator.AnimatorListener listener) {
+ mDismissState = false;
mDismissAnimationsHolder.startDismissAnimation(listener);
}
@@ -201,4 +240,70 @@
super.onDetachedFromWindow();
setDismissState(false);
}
+
+ public void reset() {
+ mDismissState = false;
+ mRecentsRowFocusAnimationHolder.reset();
+ mDismissAnimationsHolder.reset();
+ }
+
+ private void setThumbnailView() {
+ ImageView screenshotView = (ImageView) findViewById(R.id.card_view_banner_icon);
+ PackageManager pm = getContext().getPackageManager();
+ if (mTask.thumbnail != null) {
+ setAsScreenShotView(mTask.thumbnail, screenshotView);
+ } else {
+ try {
+ Drawable banner = null;
+ if (mTask.key != null) {
+ banner = pm.getActivityBanner(mTask.key.baseIntent);
+ }
+ if (banner != null) {
+ setAsBannerView(banner, screenshotView);
+ } else {
+ setAsIconView(mTask.icon, screenshotView);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Package not found : " + e);
+ setAsIconView(mTask.icon, screenshotView);
+ }
+ }
+ }
+
+ private void setAsScreenShotView(Bitmap screenshot, ImageView screenshotView) {
+ LayoutParams lp = (LayoutParams) screenshotView.getLayoutParams();
+ lp.width = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_card_width);
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_screenshot_height);
+
+ screenshotView.setLayoutParams(lp);
+ screenshotView.setImageBitmap(screenshot);
+ }
+
+ private void setAsBannerView(Drawable banner, ImageView bannerView) {
+ LayoutParams lp = (LayoutParams) bannerView.getLayoutParams();
+ lp.width = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_banner_width);
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_banner_height);
+
+ bannerView.setLayoutParams(lp);
+ bannerView.setImageDrawable(banner);
+ }
+
+ private void setAsIconView(Drawable icon, ImageView iconView) {
+ LayoutParams lp = (LayoutParams) iconView.getLayoutParams();
+ lp.width = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_fallback_icon_width);
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_fallback_icon_height);
+
+ iconView.setLayoutParams(lp);
+ iconView.setImageDrawable(icon);
+ }
+
+ public View getThumbnailView() {
+ return mThumbnailView;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
index 603721a..9f52abd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -33,9 +33,6 @@
import com.android.systemui.recents.model.TaskStack.TaskStackCallbacks;
import com.android.systemui.recents.views.AnimationProps;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Horizontal Grid View Implementation to show the Task Stack for TV.
*/
@@ -179,13 +176,14 @@
@Override
public void onStackTaskAdded(TaskStack stack, Task newTask) {
- getAdapter().notifyItemInserted(stack.getStackTasks().indexOf(newTask));
+ ((TaskStackHorizontalViewAdapter) getAdapter()).addTaskAt(newTask,
+ stack.indexOfStackTask(newTask));
}
@Override
public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture) {
- getAdapter().notifyItemRemoved(stack.getStackTasks().indexOf(removedTask));
+ ((TaskStackHorizontalViewAdapter) getAdapter()).removeTask(removedTask);
if (mFocusedTask == removedTask) {
resetFocusedTask(removedTask);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
index 97712ea..eb3b02d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -28,6 +28,7 @@
import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.views.AnimationProps;
import java.util.ArrayList;
import java.util.List;
@@ -40,10 +41,12 @@
//Full class name is 30 characters
private static final String TAG = "TaskStackViewAdapter";
private List<Task> mTaskList;
+ private TaskStackHorizontalGridView mGridView;
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private TaskCardView mTaskCardView;
private Task mTask;
+ private boolean mShouldReset;
public ViewHolder(View v) {
super(v);
if(v instanceof TaskCardView) {
@@ -62,11 +65,10 @@
try {
if (mTaskCardView.isInDismissState()) {
mTaskCardView.startDismissTaskAnimation(
- getRemoveAtListener(getAdapterPosition(), mTaskCardView));
+ getRemoveAtListener(getAdapterPosition(), mTaskCardView.getTask()));
} else {
EventBus.getDefault().send(new LaunchTvTaskEvent(mTaskCardView, mTask,
null, INVALID_STACK_ID));
- ((Activity) (v.getContext())).finish();
}
} catch (Exception e) {
Log.e(TAG, v.getContext()
@@ -74,6 +76,29 @@
}
}
+
+ private Animator.AnimatorListener getRemoveAtListener(final int position,
+ final Task task) {
+ return new Animator.AnimatorListener() {
+
+ @Override
+ public void onAnimationStart(Animator animation) { }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ removeAt(position);
+ EventBus.getDefault().send(new DeleteTaskDataEvent(task));
+ mShouldReset = true;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) { }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) { }
+ };
+
+ }
}
public TaskStackHorizontalViewAdapter(List tasks) {
@@ -89,9 +114,9 @@
@Override
public TaskStackHorizontalViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
- View view = LayoutInflater.from(parent.getContext())
- .inflate(R.layout.recents_tv_task_card_view, parent, false);
- ViewHolder viewHolder = new ViewHolder(view);
+ LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ ViewHolder viewHolder = new ViewHolder(
+ inflater.inflate(R.layout.recents_tv_task_card_view, parent, false));
return viewHolder;
}
@@ -101,39 +126,49 @@
}
@Override
+ public void onViewDetachedFromWindow(ViewHolder holder) {
+ // We only want to reset on view detach if this is the last task being dismissed.
+ // This is so that we do not reset when shifting to apps etc, as it is not needed.
+ if (holder.mShouldReset) {
+ holder.mTaskCardView.reset();
+ holder.mShouldReset = false;
+ }
+ }
+
+ @Override
public int getItemCount() {
return mTaskList.size();
}
- private Animator.AnimatorListener getRemoveAtListener(final int position,
- final TaskCardView taskCardView) {
- return new Animator.AnimatorListener() {
-
- @Override
- public void onAnimationStart(Animator animation) { }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- removeAt(position);
- EventBus.getDefault().send(new DeleteTaskDataEvent(taskCardView.getTask()));
- }
-
- @Override
- public void onAnimationCancel(Animator animation) { }
-
- @Override
- public void onAnimationRepeat(Animator animation) { }
- };
-
+ private void removeAt(int position) {
+ Task removedTask = mTaskList.remove(position);
+ if (mGridView != null) {
+ mGridView.getStack().removeTask(removedTask, AnimationProps.IMMEDIATE,
+ false);
+ }
+ notifyItemRemoved(position);
}
- private void removeAt(int position) {
- mTaskList.remove(position);
- notifyItemRemoved(position);
+ public void removeTask(Task task) {
+ int position = mTaskList.indexOf(task);
+ if (position >= 0) {
+ mTaskList.remove(position);
+ notifyItemRemoved(position);
+ }
}
public int getPositionOfTask(Task task) {
int position = mTaskList.indexOf(task);
return (position >= 0) ? position : 0;
}
+
+
+ public void setTaskStackHorizontalGridView(TaskStackHorizontalGridView gridView) {
+ mGridView = gridView;
+ }
+
+ public void addTaskAt(Task task, int position) {
+ mTaskList.add(position, task);
+ notifyItemInserted(position);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 21a43d5..86d68c2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -540,7 +540,8 @@
mTransitionHelper.wrapStartedListener(startedListener),
true /* scaleUp */);
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
+ event.task.getTopComponent().flattenToShortString());
} else {
// Animate the overlay alpha back to 0
updateVisibleDockRegions(null, true /* isDefaultDockState */, -1,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 22acb88..70c4dbd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -41,7 +41,6 @@
import java.util.ArrayList;
-
/**
* Represents the dock regions for each orientation.
*/
@@ -163,6 +162,8 @@
mVisibleDockStates.clear();
if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask()
&& mDividerSnapAlgorithm.isSplitScreenFeasible()) {
+ Recents.logDockAttempt(mRv.getContext(), event.task.getTopComponent(),
+ event.task.resizeMode);
if (!event.task.isDockable) {
EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent());
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 07a1d4e..dce2353 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -152,7 +152,7 @@
/**
* Animates the scrim to match the state of the current nav bar.
*/
- private void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
+ public void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
boolean hasNavBarScrim = isNavBarScrimRequired(hasStackTasks);
if (mHasNavBarScrim != hasNavBarScrim) {
AnimationProps animation = hasNavBarScrim
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index fe91f42..76aab59d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.Log;
import android.view.View;
@@ -77,7 +78,7 @@
public static final int ENTER_FROM_HOME_ALPHA_DURATION = 100;
public static final int ENTER_FROM_HOME_TRANSLATION_DURATION = 333;
- public static final int ENTER_WHILE_DOCKING_DURATION = 150;
+ public static final int ENTER_WHILE_DOCKING_DURATION = 250;
private static final PathInterpolator ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR =
new PathInterpolator(0, 0, 0, 1f);
@@ -135,6 +136,8 @@
R.dimen.recents_task_stack_animation_affiliate_enter_offset);
int launchedWhileDockingOffset = res.getDimensionPixelSize(
R.dimen.recents_task_stack_animation_launched_while_docking_offset);
+ boolean isLandscape = mStackView.getContext().getApplicationContext().getResources()
+ .getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
// Prepare each of the task views for their enter animation from front to back
List<TaskView> taskViews = mStackView.getTaskViews();
@@ -169,7 +172,10 @@
mTmpTransform.alpha = 0f;
mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE);
} else if (launchState.launchedViaDockGesture) {
- mTmpTransform.rect.offset(0, launchedWhileDockingOffset);
+ int offset = isLandscape
+ ? launchedWhileDockingOffset
+ : (int) (offscreenYOffset * 0.9f);
+ mTmpTransform.rect.offset(0, offset);
mTmpTransform.alpha = 0f;
mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index b75a91e..e4da8b3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -23,13 +23,13 @@
import android.graphics.Path;
import android.graphics.Rect;
import android.util.ArraySet;
+import android.util.MutableFloat;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.ViewDebug;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsDebugFlags;
@@ -628,22 +628,24 @@
/**
* Updates this stack when a scroll happens.
+ *
*/
- public void updateFocusStateOnScroll(float stackScroll, float deltaScroll) {
- if (deltaScroll == 0f) {
- return;
+ public float updateFocusStateOnScroll(float lastTargetStackScroll, float targetStackScroll,
+ float lastStackScroll) {
+ if (targetStackScroll == lastStackScroll) {
+ return targetStackScroll;
}
+ float deltaScroll = targetStackScroll - lastStackScroll;
+ float deltaTargetScroll = targetStackScroll - lastTargetStackScroll;
+ float newScroll = targetStackScroll;
+ mUnfocusedRange.offset(targetStackScroll);
for (int i = mTaskIndexOverrideMap.size() - 1; i >= 0; i--) {
int taskId = mTaskIndexOverrideMap.keyAt(i);
float x = mTaskIndexMap.get(taskId);
float overrideX = mTaskIndexOverrideMap.get(taskId, 0f);
float newOverrideX = overrideX + deltaScroll;
- mUnfocusedRange.offset(stackScroll);
- boolean outOfBounds = mUnfocusedRange.getNormalizedX(newOverrideX) < 0f ||
- mUnfocusedRange.getNormalizedX(newOverrideX) > 1f;
- if (outOfBounds || (overrideX >= x && x >= newOverrideX) ||
- (overrideX <= x && x <= newOverrideX)) {
+ if (isInvalidOverrideX(x, overrideX, newOverrideX)) {
// Remove the override once we reach the original task index
mTaskIndexOverrideMap.removeAt(i);
} else if ((overrideX >= x && deltaScroll <= 0f) ||
@@ -652,11 +654,23 @@
mTaskIndexOverrideMap.put(taskId, newOverrideX);
} else {
// Scrolling override x away from x, we should still move the scroll towards x
- float deltaX = overrideX - x;
- newOverrideX = Math.signum(deltaX) * (Math.abs(deltaX) - Math.abs(deltaScroll));
- mTaskIndexOverrideMap.put(taskId, x + newOverrideX);
+ newScroll = lastStackScroll;
+ newOverrideX = overrideX - deltaTargetScroll;
+ if (isInvalidOverrideX(x, overrideX, newOverrideX)) {
+ mTaskIndexOverrideMap.removeAt(i);
+ } else{
+ mTaskIndexOverrideMap.put(taskId, newOverrideX);
+ }
}
}
+ return newScroll;
+ }
+
+ private boolean isInvalidOverrideX(float x, float overrideX, float newOverrideX) {
+ boolean outOfBounds = mUnfocusedRange.getNormalizedX(newOverrideX) < 0f ||
+ mUnfocusedRange.getNormalizedX(newOverrideX) > 1f;
+ return outOfBounds || (overrideX >= x && x >= newOverrideX) ||
+ (overrideX <= x && x <= newOverrideX);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 13c8403..63018c5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -353,8 +353,8 @@
public void updateToInitialState(boolean scrollToInitialState) {
if (scrollToInitialState) {
mStackScroller.setStackScrollToInitialState();
+ mLayoutAlgorithm.updateToInitialState(mStack.getStackTasks());
}
- mLayoutAlgorithm.updateToInitialState(mStack.getStackTasks());
}
/** Updates the list of task views */
@@ -1221,7 +1221,9 @@
// TaskViews with the stack so that we can lay them out
if (mAwaitingFirstLayout || mInitialState != INITIAL_STATE_UPDATE_NONE) {
updateToInitialState(mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY);
- mInitialState = INITIAL_STATE_UPDATE_NONE;
+ if (!mAwaitingFirstLayout) {
+ mInitialState = INITIAL_STATE_UPDATE_NONE;
+ }
}
// Rebind all the views, including the ignore ones
@@ -1281,6 +1283,7 @@
if (mAwaitingFirstLayout || !mEnterAnimationComplete) {
mAwaitingFirstLayout = false;
+ mInitialState = INITIAL_STATE_UPDATE_NONE;
onFirstLayout();
}
}
@@ -1618,7 +1621,6 @@
if (animation != null) {
relayoutTaskViewsOnNextFrame(animation);
}
- mLayoutAlgorithm.updateFocusStateOnScroll(curScroll, curScroll - prevScroll);
if (mEnterAnimationComplete) {
if (prevScroll > SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
@@ -1837,9 +1839,17 @@
// Calculate the new task stack bounds that matches the window size that Recents will
// have after the drop
final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
+ Rect systemInsets = new Rect(mStableLayoutAlgorithm.mSystemInsets);
+ // When docked, the nav bar insets are consumed and the activity is measured without
+ // insets. However, the window bounds include the insets, so we need to subtract them
+ // here to make them identical.
+ int height = getMeasuredHeight();
+ height -= systemInsets.bottom;
+ systemInsets.bottom = 0;
mStackBounds.set(dockState.getDockedTaskStackBounds(getMeasuredWidth(),
- getMeasuredHeight(), mDividerSize, mLayoutAlgorithm.mSystemInsets,
+ height, mDividerSize, mLayoutAlgorithm.mSystemInsets,
mLayoutAlgorithm, getResources(), mWindowRect));
+ mLayoutAlgorithm.setSystemInsets(systemInsets);
mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
updateLayoutAlgorithm(true /* boundScroll */);
@@ -1850,6 +1860,7 @@
mWindowRect.set(mStableWindowRect);
mStackBounds.set(mStableStackBounds);
removeIgnoreTask(event.task);
+ mLayoutAlgorithm.setSystemInsets(mStableLayoutAlgorithm.mSystemInsets);
mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
updateLayoutAlgorithm(true /* boundScroll */);
@@ -1988,8 +1999,7 @@
}
public final void onBusEvent(ConfigurationChangedEvent event) {
- mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
- mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+ reloadOnConfigurationChange();
// Notify the task views of the configuration change so they can reload their resources
if (!event.fromMultiWindow) {
@@ -2003,12 +2013,15 @@
}
// Trigger a new layout and update to the initial state if necessary
- if (event.fromMultiWindow) {
- mInitialState = INITIAL_STATE_UPDATE_ALL;
- } else if (event.fromOrientationChange) {
+ if (event.fromMultiWindow || event.fromOrientationChange) {
mInitialState = INITIAL_STATE_UPDATE_LAYOUT_ONLY;
+ requestLayout();
}
- requestLayout();
+ }
+
+ public void reloadOnConfigurationChange() {
+ mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+ mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 19b3c94..1fa73c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.util.FloatProperty;
import android.util.Log;
+import android.util.MutableFloat;
import android.util.Property;
import android.view.ViewDebug;
import android.widget.OverScroller;
@@ -66,6 +67,8 @@
@ViewDebug.ExportedProperty(category="recents")
float mStackScrollP;
+ @ViewDebug.ExportedProperty(category="recents")
+ float mLastDeltaP = 0f;
float mFlingDownScrollP;
int mFlingDownY;
@@ -84,6 +87,11 @@
/** Resets the task scroller. */
void reset() {
mStackScrollP = 0f;
+ mLastDeltaP = 0f;
+ }
+
+ void resetDeltaScroll() {
+ mLastDeltaP = 0f;
}
/** Gets the current stack scroll */
@@ -99,14 +107,27 @@
}
/**
+ * Sets the current stack scroll immediately, and returns the difference between the target
+ * scroll and the actual scroll after accounting for the effect on the focus state.
+ */
+ public float setDeltaStackScroll(float downP, float deltaP) {
+ float targetScroll = downP + deltaP;
+ float newScroll = mLayoutAlgorithm.updateFocusStateOnScroll(downP + mLastDeltaP, targetScroll,
+ mStackScrollP);
+ setStackScroll(newScroll, AnimationProps.IMMEDIATE);
+ mLastDeltaP = deltaP;
+ return newScroll - targetScroll;
+ }
+
+ /**
* Sets the current stack scroll, but indicates to the callback the preferred animation to
* update to this new scroll.
*/
- public void setStackScroll(float s, AnimationProps animation) {
- float prevStackScroll = mStackScrollP;
- mStackScrollP = s;
+ public void setStackScroll(float newScroll, AnimationProps animation) {
+ float prevScroll = mStackScrollP;
+ mStackScrollP = newScroll;
if (mCb != null) {
- mCb.onStackScrollChanged(prevStackScroll, mStackScrollP, animation);
+ mCb.onStackScrollChanged(prevScroll, mStackScrollP, animation);
}
}
@@ -115,9 +136,9 @@
* @return whether the stack progress changed.
*/
public boolean setStackScrollToInitialState() {
- float prevStackScrollP = mStackScrollP;
+ float prevScroll = mStackScrollP;
setStackScroll(mLayoutAlgorithm.mInitialScrollP);
- return Float.compare(prevStackScrollP, mStackScrollP) != 0;
+ return Float.compare(prevScroll, mStackScrollP) != 0;
}
/**
@@ -227,10 +248,9 @@
boolean computeScroll() {
if (mScroller.computeScrollOffset()) {
float deltaP = mLayoutAlgorithm.getDeltaPForY(mFlingDownY, mScroller.getCurrY());
- float scroll = mFlingDownScrollP + deltaP;
- setStackScroll(scroll);
+ mFlingDownScrollP += setDeltaStackScroll(mFlingDownScrollP, deltaP);
if (DEBUG) {
- Log.d(TAG, "computeScroll: " + scroll);
+ Log.d(TAG, "computeScroll: " + (mFlingDownScrollP + deltaP));
}
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index ee0de1a..3cdb1fb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -200,6 +200,7 @@
// Stop the current scroll if it is still flinging
mScroller.stopScroller();
mScroller.stopBoundScrollAnimation();
+ mScroller.resetDeltaScroll();
Utilities.cancelAnimationWithoutCallbacks(mScrollFlingAnimator);
// Finish any existing task animations from the delete
@@ -223,6 +224,7 @@
mDownY = (int) ev.getY(index);
mLastY = mDownY;
mDownScrollP = mScroller.getStackScroll();
+ mScroller.resetDeltaScroll();
mVelocityTracker.addMovement(ev);
break;
}
@@ -256,20 +258,21 @@
// If we just move linearly on the screen, then that would map to 1/arclength
// of the curve, so just move the scroll proportional to that
float deltaP = layoutAlgorithm.getDeltaPForY(mDownY, y);
- float curScrollP = mDownScrollP + deltaP;
// Modulate the overscroll to prevent users from pulling the stack too far
float minScrollP = layoutAlgorithm.mMinScrollP;
float maxScrollP = layoutAlgorithm.mMaxScrollP;
+ float curScrollP = mDownScrollP + deltaP;
if (curScrollP < minScrollP || curScrollP > maxScrollP) {
float clampedScrollP = Utilities.clamp(curScrollP, minScrollP, maxScrollP);
float overscrollP = (curScrollP - clampedScrollP);
float overscrollX = Math.abs(overscrollP) / MAX_OVERSCROLL;
- curScrollP = clampedScrollP + (Math.signum(overscrollP) *
- (OVERSCROLL_INTERP.getInterpolation(overscrollX) * MAX_OVERSCROLL));
+ float interpX = OVERSCROLL_INTERP.getInterpolation(overscrollX);
+ curScrollP = clampedScrollP + Math.signum(overscrollP) *
+ (interpX * MAX_OVERSCROLL);
}
-
- mScroller.setStackScroll(curScrollP);
+ mDownScrollP += mScroller.setDeltaStackScroll(mDownScrollP,
+ curScrollP - mDownScrollP);
mStackViewScrolledEvent.updateY(y - mLastY);
EventBus.getDefault().send(mStackViewScrolledEvent);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 16d8e53..f98d3d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -280,27 +280,31 @@
/**
* Update the header view when the configuration changes.
*/
- void onConfigurationChanged() {
+ public void onConfigurationChanged() {
// Update the dimensions of everything in the header. We do this because we need to use
// resources for the display, and not the current configuration.
Resources res = getResources();
- mHeaderBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+ int headerBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
R.dimen.recents_task_view_header_height,
R.dimen.recents_task_view_header_height,
R.dimen.recents_task_view_header_height,
R.dimen.recents_task_view_header_height_tablet_land,
R.dimen.recents_task_view_header_height,
R.dimen.recents_task_view_header_height_tablet_land);
- mHeaderButtonPadding = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+ int headerButtonPadding = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
R.dimen.recents_task_view_header_button_padding,
R.dimen.recents_task_view_header_button_padding,
R.dimen.recents_task_view_header_button_padding,
R.dimen.recents_task_view_header_button_padding_tablet_land,
R.dimen.recents_task_view_header_button_padding,
R.dimen.recents_task_view_header_button_padding_tablet_land);
- updateLayoutParams(mIconView, mTitleView, mMoveTaskButton, mDismissButton);
- if (mAppOverlayView != null) {
- updateLayoutParams(mAppIconView, mAppTitleView, null, mAppInfoView);
+ if (headerBarHeight != mHeaderBarHeight || headerButtonPadding != mHeaderButtonPadding) {
+ mHeaderBarHeight = headerBarHeight;
+ mHeaderButtonPadding = headerButtonPadding;
+ updateLayoutParams(mIconView, mTitleView, mMoveTaskButton, mDismissButton);
+ if (mAppOverlayView != null) {
+ updateLayoutParams(mAppIconView, mAppTitleView, null, mAppInfoView);
+ }
}
}
@@ -434,7 +438,6 @@
/** Binds the bar view to the task */
public void rebindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) {
- SystemServicesProxy ssp = Recents.getSystemServices();
mTask = t;
// If an activity icon is defined, then we use that as the primary icon to show in the bar,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index e5ac0d3..62fd585 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -143,43 +143,28 @@
int viewWidth = mTaskViewRect.width();
int viewHeight = mTaskViewRect.height();
- if (mBitmapShader != null) {
-
- // We are drawing the thumbnail in the same orientation, so just fit the width
- int thumbnailWidth = (int) (mThumbnailRect.width() * mThumbnailScale);
- int thumbnailHeight = (int) (mThumbnailRect.height() * mThumbnailScale);
-
- if (thumbnailWidth >= viewWidth && thumbnailHeight >= viewHeight) {
- // Thumbnail fills the full task view bounds, so just draw it
- canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
- mDrawPaint);
- } else {
- // Thumbnail does not fill the full task view bounds, so just draw it and fill the
- // empty areas with the background color
- int count = canvas.save();
-
- // Since we only want the top corners to be rounded, draw slightly beyond the
- // thumbnail height, but clip to the thumbnail height
- canvas.clipRect(0, 0, thumbnailWidth, thumbnailHeight, Region.Op.REPLACE);
- canvas.drawRoundRect(0, 0,
- thumbnailWidth + (thumbnailWidth < viewWidth ? mCornerRadius : 0),
- thumbnailHeight + (thumbnailHeight < viewHeight ? mCornerRadius : 0),
- mCornerRadius, mCornerRadius, mDrawPaint);
-
- // In the remaining space, draw the background color
- if (thumbnailWidth < viewWidth) {
- canvas.clipRect(thumbnailWidth, 0, viewWidth, viewHeight, Region.Op.REPLACE);
- canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), 0,
- viewWidth, viewHeight, mCornerRadius, mCornerRadius, mBgFillPaint);
- }
- if (thumbnailWidth > 0 && thumbnailHeight < viewHeight) {
- canvas.clipRect(0, thumbnailHeight, viewWidth, viewHeight, Region.Op.REPLACE);
- canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
- viewWidth, viewHeight, mCornerRadius, mCornerRadius, mBgFillPaint);
- }
-
- canvas.restoreToCount(count);
+ int thumbnailWidth = Math.min(viewWidth,
+ (int) (mThumbnailRect.width() * mThumbnailScale));
+ int thumbnailHeight = Math.min(viewHeight,
+ (int) (mThumbnailRect.height() * mThumbnailScale));
+ if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) {
+ // Draw the background, there will be some small overdraw with the thumbnail
+ if (thumbnailWidth < viewWidth) {
+ // Portrait thumbnail on a landscape task view
+ canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), 0,
+ viewWidth, viewHeight,
+ mCornerRadius, mCornerRadius, mBgFillPaint);
}
+ if (thumbnailHeight < viewHeight) {
+ // Landscape thumbnail on a portrait task view
+ canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
+ viewWidth, viewHeight,
+ mCornerRadius, mCornerRadius, mBgFillPaint);
+ }
+
+ // Draw the thumbnail
+ canvas.drawRoundRect(0, 0, thumbnailWidth, thumbnailHeight,
+ mCornerRadius, mCornerRadius, mDrawPaint);
} else {
canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
mBgFillPaint);
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 69dcabe..0aeb7b4 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -102,8 +102,8 @@
int dockMode = (shortcutCode == SC_DOCK_LEFT)
? ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
: ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
- recents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, dockMode, null);
- MetricsLogger.action(mContext, MetricsEvent.WINDOW_DOCK_SHORTCUTS);
+ recents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, dockMode, null,
+ MetricsEvent.WINDOW_DOCK_SHORTCUTS);
} else {
// If there is already a docked window, we respond by resizing the docking pane.
DividerView dividerView = getComponent(Divider.class).getView();
@@ -115,7 +115,8 @@
DividerSnapAlgorithm.SnapTarget target = snapAlgorithm.cycleNonDismissTarget(
currentTarget, increment);
dividerView.startDragging(true /* animate */, false /* touching */);
- dividerView.stopDragging(target.position, 0f, true /* avoidDismissStart */);
+ dividerView.stopDragging(target.position, 0f, true /* avoidDismissStart */,
+ true /* logMetrics */);
}
} catch (RemoteException e) {
Log.e(TAG, "handleDockKey() failed.");
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index d294c80..2bf0b40 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -146,5 +146,10 @@
throws RemoteException {
updateMinimizedDockedStack(minimized, animDuration);
}
+
+ @Override
+ public void onDockSideChanged(final int newDockSide) throws RemoteException {
+ mView.post(() -> mView.notifyDockSideChanged(newDockSide));
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 98e0dd9..66a413c 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -54,11 +54,14 @@
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.recents.Constants.Metrics;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
@@ -80,7 +83,13 @@
static final long TOUCH_ANIMATION_DURATION = 150;
static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
- private static final String TAG = "DividerView";
+ private static final int LOG_VALUE_RESIZE_50_50 = 0;
+ private static final int LOG_VALUE_RESIZE_DOCKED_SMALLER = 1;
+ private static final int LOG_VALUE_RESIZE_DOCKED_LARGER = 2;
+
+ private static final int LOG_VALUE_UNDOCK_MAX_DOCKED = 0;
+ private static final int LOG_VALUE_UNDOCK_MAX_OTHER = 1;
+
private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
private static final boolean SWAPPING_ENABLED = false;
@@ -88,7 +97,7 @@
/**
* How much the background gets scaled when we are in the minimized dock state.
*/
- private static final float MINIMIZE_DOCK_SCALE = 0.375f;
+ private static final float MINIMIZE_DOCK_SCALE = 0f;
private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
new PathInterpolator(0.5f, 1f, 0.5f, 1f);
@@ -97,6 +106,7 @@
private DividerHandleView mHandle;
private View mBackground;
+ private MinimizedDockShadow mMinimizedShadow;
private int mStartX;
private int mStartY;
private int mStartPosition;
@@ -133,6 +143,8 @@
private boolean mGrowRecents;
private ValueAnimator mCurrentAnimator;
private boolean mEntranceAnimationRunning;
+ private boolean mExitAnimationRunning;
+ private int mExitStartPosition;
private GestureDetector mGestureDetector;
private boolean mDockedStackMinimized;
@@ -201,6 +213,7 @@
super.onFinishInflate();
mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle);
mBackground = findViewById(R.id.docked_divider_background);
+ mMinimizedShadow = (MinimizedDockShadow) findViewById(R.id.minimized_dock_shadow);
mHandle.setOnTouchListener(this);
mDividerWindowWidth = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
@@ -267,6 +280,18 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
+ int minimizeLeft = 0;
+ int minimizeTop = 0;
+ if (mDockSide == WindowManager.DOCKED_TOP) {
+ minimizeTop = mBackground.getTop();
+ } else if (mDockSide == WindowManager.DOCKED_LEFT) {
+ minimizeLeft = mBackground.getLeft();
+ } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
+ minimizeLeft = mBackground.getRight() - mMinimizedShadow.getWidth();
+ }
+ mMinimizedShadow.layout(minimizeLeft, minimizeTop,
+ minimizeLeft + mMinimizedShadow.getMeasuredWidth(),
+ minimizeTop + mMinimizedShadow.getMeasuredHeight());
if (changed) {
mWindowManagerProxy.setTouchRegion(new Rect(mHandle.getLeft(), mHandle.getTop(),
mHandle.getRight(), mHandle.getBottom()));
@@ -297,22 +322,28 @@
return mDockSide != WindowManager.DOCKED_INVALID;
}
- public void stopDragging(int position, float velocity, boolean avoidDismissStart) {
+ public void stopDragging(int position, float velocity, boolean avoidDismissStart,
+ boolean logMetrics) {
mHandle.setTouching(false, true /* animate */);
- fling(position, velocity, avoidDismissStart);
+ fling(position, velocity, avoidDismissStart, logMetrics);
mWindowManager.setSlippery(true);
releaseBackground();
}
public void stopDragging(int position, SnapTarget target, long duration,
Interpolator interpolator) {
- stopDragging(position, target, duration, 0 /* startDelay*/, interpolator);
+ stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator);
+ }
+
+ public void stopDragging(int position, SnapTarget target, long duration,
+ Interpolator interpolator, long endDelay) {
+ stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator);
}
public void stopDragging(int position, SnapTarget target, long duration, long startDelay,
- Interpolator interpolator) {
+ long endDelay, Interpolator interpolator) {
mHandle.setTouching(false, true /* animate */);
- flingTo(position, target, duration, startDelay, interpolator);
+ flingTo(position, target, duration, startDelay, endDelay, interpolator);
mWindowManager.setSlippery(true);
releaseBackground();
}
@@ -325,6 +356,7 @@
private void updateDockSide() {
mDockSide = mWindowManagerProxy.getDockSide();
+ mMinimizedShadow.setDockSide(mDockSide);
}
private void initializeSnapAlgorithm() {
@@ -396,37 +428,70 @@
mVelocityTracker.computeCurrentVelocity(1000);
int position = calculatePosition(x, y);
stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
- : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */);
+ : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */,
+ true /* log */);
mMoving = false;
break;
}
return true;
}
+ private void logResizeEvent(SnapTarget snapTarget) {
+ if (snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
+ MetricsLogger.action(
+ mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideTopLeft(mDockSide)
+ ? LOG_VALUE_UNDOCK_MAX_OTHER
+ : LOG_VALUE_UNDOCK_MAX_DOCKED);
+ } else if (snapTarget == mSnapAlgorithm.getDismissEndTarget()) {
+ MetricsLogger.action(
+ mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideBottomRight(mDockSide)
+ ? LOG_VALUE_UNDOCK_MAX_OTHER
+ : LOG_VALUE_UNDOCK_MAX_DOCKED);
+ } else if (snapTarget == mSnapAlgorithm.getMiddleTarget()) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
+ LOG_VALUE_RESIZE_50_50);
+ } else if (snapTarget == mSnapAlgorithm.getFirstSplitTarget()) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
+ dockSideTopLeft(mDockSide)
+ ? LOG_VALUE_RESIZE_DOCKED_SMALLER
+ : LOG_VALUE_RESIZE_DOCKED_LARGER);
+ } else if (snapTarget == mSnapAlgorithm.getLastSplitTarget()) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE,
+ dockSideTopLeft(mDockSide)
+ ? LOG_VALUE_RESIZE_DOCKED_LARGER
+ : LOG_VALUE_RESIZE_DOCKED_SMALLER);
+ }
+ }
+
private void convertToScreenCoordinates(MotionEvent event) {
event.setLocation(event.getRawX(), event.getRawY());
}
- private void fling(int position, float velocity, boolean avoidDismissStart) {
+ private void fling(int position, float velocity, boolean avoidDismissStart,
+ boolean logMetrics) {
SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
snapTarget = mSnapAlgorithm.getFirstSplitTarget();
}
- ValueAnimator anim = getFlingAnimator(position, snapTarget);
+ if (logMetrics) {
+ logResizeEvent(snapTarget);
+ }
+ ValueAnimator anim = getFlingAnimator(position, snapTarget, 0 /* endDelay */);
mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
anim.start();
}
private void flingTo(int position, SnapTarget target, long duration, long startDelay,
- Interpolator interpolator) {
- ValueAnimator anim = getFlingAnimator(position, target);
+ long endDelay, Interpolator interpolator) {
+ ValueAnimator anim = getFlingAnimator(position, target, endDelay);
anim.setDuration(duration);
anim.setStartDelay(startDelay);
anim.setInterpolator(interpolator);
anim.start();
}
- private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget) {
+ private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget,
+ final long endDelay) {
ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
@@ -437,15 +502,31 @@
: snapTarget.position, snapTarget);
}
});
+ Runnable endAction = () -> {
+ commitSnapFlags(snapTarget);
+ mWindowManagerProxy.setResizing(false);
+ mDockSide = WindowManager.DOCKED_INVALID;
+ mCurrentAnimator = null;
+ mEntranceAnimationRunning = false;
+ mExitAnimationRunning = false;
+ EventBus.getDefault().send(new StoppedDragingEvent());
+ };
anim.addListener(new AnimatorListenerAdapter() {
+
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
- commitSnapFlags(snapTarget);
- mWindowManagerProxy.setResizing(false);
- mDockSide = WindowManager.DOCKED_INVALID;
- mCurrentAnimator = null;
- mEntranceAnimationRunning = false;
- EventBus.getDefault().send(new StoppedDragingEvent());
+ if (endDelay == 0 || mCancelled) {
+ endAction.run();
+ } else {
+ postDelayed(endAction, endDelay);
+ }
}
});
mCurrentAnimator = anim;
@@ -538,6 +619,7 @@
: mBackground.getWidth());
mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
}
+ mMinimizedShadow.setAlpha(minimized ? 1f : 0f);
mDockedStackMinimized = minimized;
}
@@ -563,6 +645,11 @@
if (!minimized) {
mBackground.animate().withEndAction(mResetBackgroundRunnable);
}
+ mMinimizedShadow.animate()
+ .alpha(minimized ? 1f : 0f)
+ .setInterpolator(Interpolators.ALPHA_IN)
+ .setDuration(animDuration)
+ .start();
mBackground.animate()
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(animDuration)
@@ -575,6 +662,7 @@
mBackground.setPivotY(mBackground.getHeight() / 2);
mBackground.setScaleX(1f);
mBackground.setScaleY(1f);
+ mMinimizedShadow.setAlpha(0f);
}
@Override
@@ -583,6 +671,13 @@
updateDisplayInfo();
}
+
+ public void notifyDockSideChanged(int newDockSide) {
+ mDockSide = newDockSide;
+ mMinimizedShadow.setDockSide(mDockSide);
+ requestLayout();
+ }
+
private void updateDisplayInfo() {
final DisplayManager displayManager =
(DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
@@ -654,6 +749,15 @@
mOtherTaskRect);
mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
mOtherTaskRect, null);
+ } else if (mExitAnimationRunning && taskPosition != TASK_POSITION_SAME) {
+ calculateBoundsForPosition(taskPosition,
+ mDockSide, mDockedTaskRect);
+ calculateBoundsForPosition(mExitStartPosition,
+ DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
+ mOtherInsetRect.set(mOtherTaskRect);
+ applyExitAnimationParallax(mOtherTaskRect, position);
+ mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
+ mOtherTaskRect, mOtherInsetRect);
} else if (taskPosition != TASK_POSITION_SAME) {
calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
mOtherRect);
@@ -692,6 +796,16 @@
dimFraction);
}
+ private void applyExitAnimationParallax(Rect taskRect, int position) {
+ if (mDockSide == WindowManager.DOCKED_TOP) {
+ taskRect.offset(0, (int) ((position - mExitStartPosition) * 0.25f));
+ } else if (mDockSide == WindowManager.DOCKED_LEFT) {
+ taskRect.offset((int) ((position - mExitStartPosition) * 0.25f), 0);
+ } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
+ taskRect.offset((int) ((mExitStartPosition - position) * 0.25f), 0);
+ }
+ }
+
private float getDimFraction(int position, SnapTarget dismissTarget) {
if (mEntranceAnimationRunning) {
return 0f;
@@ -875,14 +989,17 @@
if (mAnimateAfterRecentsDrawn) {
mAnimateAfterRecentsDrawn = false;
updateDockSide();
- stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
- Interpolators.TOUCH_RESPONSE);
+
+ // Delay switching resizing mode because this might cause jank in recents animation
+ // that's long than this animation.
+ stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(),
+ 250 /* startDelay */, Interpolators.FAST_OUT_SLOW_IN, 200 /* endDelay */);
}
if (mGrowAfterRecentsDrawn) {
mGrowAfterRecentsDrawn = false;
updateDockSide();
stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
- Interpolators.TOUCH_RESPONSE);
+ Interpolators.FAST_OUT_SLOW_IN);
}
}
@@ -895,8 +1012,10 @@
: mSnapAlgorithm.getDismissStartTarget();
// Don't start immediately - give a little bit time to settle the drag resize change.
- stopDragging(getCurrentPosition(), target, 336 /* duration */, 100 /* startDelay */,
- Interpolators.TOUCH_RESPONSE);
+ mExitAnimationRunning = true;
+ mExitStartPosition = getCurrentPosition();
+ stopDragging(mExitStartPosition, target, 336 /* duration */, 100 /* startDelay */,
+ 0 /* endDelay */, Interpolators.FAST_OUT_SLOW_IN);
// Vibrate after undocking
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/MinimizedDockShadow.java b/packages/SystemUI/src/com/android/systemui/stackdivider/MinimizedDockShadow.java
new file mode 100644
index 0000000..ecff54f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/MinimizedDockShadow.java
@@ -0,0 +1,99 @@
+/*
+ * 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
+ */
+
+package com.android.systemui.stackdivider;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+/**
+ * Shadow for the minimized dock state on homescreen.
+ */
+public class MinimizedDockShadow extends View {
+
+ private final Paint mShadowPaint = new Paint();
+
+ private int mDockSide = WindowManager.DOCKED_INVALID;
+
+ public MinimizedDockShadow(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setDockSide(int dockSide) {
+ if (dockSide != mDockSide) {
+ mDockSide = dockSide;
+ updatePaint(getLeft(), getTop(), getRight(), getBottom());
+ invalidate();
+ }
+ }
+
+ private void updatePaint(int left, int top, int right, int bottom) {
+ int startColor = mContext.getResources().getColor(
+ R.color.minimize_dock_shadow_start, null);
+ int endColor = mContext.getResources().getColor(
+ R.color.minimize_dock_shadow_end, null);
+ final int middleColor = Color.argb(
+ (Color.alpha(startColor) + Color.alpha(endColor)) / 2, 0, 0, 0);
+ final int quarter = Color.argb(
+ (int) (Color.alpha(startColor) * 0.25f + Color.alpha(endColor) * 0.75f),
+ 0, 0, 0);
+ if (mDockSide == WindowManager.DOCKED_TOP) {
+ mShadowPaint.setShader(new LinearGradient(
+ 0, 0, 0, bottom - top,
+ new int[] { startColor, middleColor, quarter, endColor },
+ new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
+ } else if (mDockSide == WindowManager.DOCKED_LEFT) {
+ mShadowPaint.setShader(new LinearGradient(
+ 0, 0, right - left, 0,
+ new int[] { startColor, middleColor, quarter, endColor },
+ new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
+ } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
+ mShadowPaint.setShader(new LinearGradient(
+ right - left, 0, 0, 0,
+ new int[] { startColor, middleColor, quarter, endColor },
+ new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (changed) {
+ updatePaint(left, top, right, bottom);
+ invalidate();
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ canvas.drawRect(0, 0, getWidth(), getHeight(), mShadowPaint);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3ac7b26..237ca5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1230,7 +1230,7 @@
@Override
public void toggleSplitScreen() {
- toggleSplitScreenMode();
+ toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
}
@Override
@@ -1306,9 +1306,12 @@
/**
* Toggle docking the app window
*
- * @return {@code true} if the app window is docked after the toggle, {@code false} otherwise.
+ * @param metricsDockAction the action to log when docking is successful, or -1 to not log
+ * anything on successful docking
+ * @param metricsUndockAction the action to log when undocking, or -1 to not log anything when
+ * undocking
*/
- protected abstract boolean toggleSplitScreenMode();
+ protected abstract void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction);
/** Proxy for RecentsComponent */
@@ -1338,7 +1341,7 @@
}
protected void toggleKeyboardShortcuts(int deviceId) {
- getKeyboardShortcuts().toggleKeyboardShortcuts(deviceId);
+ KeyboardShortcuts.toggle(mContext, deviceId);
}
protected void cancelPreloadingRecents() {
@@ -1572,7 +1575,11 @@
row.setRemoteInputController(mRemoteInputController);
row.setOnExpandClickListener(this);
- // Get the app name
+ // Get the app name.
+ // Note that Notification.Builder#bindHeaderAppName has similar logic
+ // but since this field is used in the guts, it must be accurate.
+ // Therefore we will only show the application label, or, failing that, the
+ // package name. No substitutions.
final String pkg = sbn.getPackageName();
String appname = pkg;
try {
@@ -1735,14 +1742,6 @@
}
}
- protected KeyboardShortcuts getKeyboardShortcuts() {
- if (mKeyboardShortcuts == null) {
- mKeyboardShortcuts = new KeyboardShortcuts(mContext);
- }
-
- return mKeyboardShortcuts;
- }
-
public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
if (!isDeviceProvisioned()) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index c2521b3..79e06c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -70,6 +70,10 @@
*/
public final class KeyboardShortcuts {
private static final String TAG = KeyboardShortcuts.class.getSimpleName();
+ private static final Object sLock = new Object();
+ private static KeyboardShortcuts sInstance;
+ private static boolean sIsShowing;
+
private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
private final SparseArray<String> mModifierNames = new SparseArray<>();
private final SparseArray<Drawable> mSpecialCharacterDrawables = new SparseArray<>();
@@ -80,7 +84,7 @@
private final IPackageManager mPackageManager;
private final OnClickListener mDialogCloseListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- dismissKeyboardShortcutsDialog();
+ dismissKeyboardShortcuts();
}
};
private final Comparator<KeyboardShortcutInfo> mApplicationItemsComparator =
@@ -108,12 +112,49 @@
private Dialog mKeyboardShortcutsDialog;
private KeyCharacterMap mKeyCharacterMap;
- public KeyboardShortcuts(Context context) {
+ private KeyboardShortcuts(Context context) {
this.mContext = new ContextThemeWrapper(context, android.R.style.Theme_Material_Light);
this.mPackageManager = AppGlobals.getPackageManager();
loadResources(context);
}
+ private static KeyboardShortcuts getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new KeyboardShortcuts(context);
+ }
+ return sInstance;
+ }
+
+ public static void show(Context context, int deviceId) {
+ synchronized (sLock) {
+ if (sInstance != null && !sInstance.mContext.equals(context)) {
+ dismiss();
+ }
+ getInstance(context).showKeyboardShortcuts(deviceId);
+ sIsShowing = true;
+ }
+ }
+
+ public static void toggle(Context context, int deviceId) {
+ synchronized (sLock) {
+ if (sIsShowing) {
+ dismiss();
+ } else {
+ show(context, deviceId);
+ }
+ }
+ }
+
+ public static void dismiss() {
+ synchronized (sLock) {
+ if (sInstance != null) {
+ sInstance.dismissKeyboardShortcuts();
+ sInstance = null;
+ }
+ sIsShowing = false;
+ }
+ }
+
private void loadResources(Context context) {
mSpecialCharacterNames.put(
KeyEvent.KEYCODE_HOME, context.getString(R.string.keyboard_key_home));
@@ -277,27 +318,6 @@
KeyEvent.META_META_ON, context.getDrawable(R.drawable.ic_ksh_key_meta));
}
- public void toggleKeyboardShortcuts(int deviceId) {
- retrieveKeyCharacterMap(deviceId);
- if (mKeyboardShortcutsDialog == null) {
- Recents.getSystemServices().requestKeyboardShortcuts(mContext,
- new KeyboardShortcutsReceiver() {
- @Override
- public void onKeyboardShortcutsReceived(
- final List<KeyboardShortcutGroup> result) {
- result.add(getSystemShortcuts());
- final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts();
- if (appShortcuts != null) {
- result.add(appShortcuts);
- }
- showKeyboardShortcutsDialog(result);
- }
- }, deviceId);
- } else {
- dismissKeyboardShortcutsDialog();
- }
- }
-
/**
* Retrieves a {@link KeyCharacterMap} and assigns it to mKeyCharacterMap. If the given id is an
* existing device, that device's map is used. Otherwise, it checks first all available devices
@@ -327,7 +347,24 @@
mKeyCharacterMap = inputDevice.getKeyCharacterMap();
}
- public void dismissKeyboardShortcutsDialog() {
+ private void showKeyboardShortcuts(int deviceId) {
+ retrieveKeyCharacterMap(deviceId);
+ Recents.getSystemServices().requestKeyboardShortcuts(mContext,
+ new KeyboardShortcutsReceiver() {
+ @Override
+ public void onKeyboardShortcutsReceived(
+ final List<KeyboardShortcutGroup> result) {
+ result.add(getSystemShortcuts());
+ final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts();
+ if (appShortcuts != null) {
+ result.add(appShortcuts);
+ }
+ showKeyboardShortcutsDialog(result);
+ }
+ }, deviceId);
+ }
+
+ private void dismissKeyboardShortcuts() {
if (mKeyboardShortcutsDialog != null) {
mKeyboardShortcutsDialog.dismiss();
mKeyboardShortcutsDialog = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
index 5d22faf..5f4ebd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
@@ -26,8 +26,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
- final KeyboardShortcuts keyboardShortcuts = new KeyboardShortcuts(context);
- keyboardShortcuts.toggleKeyboardShortcuts(-1 /* deviceId unknown */);
+ KeyboardShortcuts.show(context, -1 /* deviceId unknown */);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 5b00523..491ffde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -348,6 +348,12 @@
setVisible(isShown());
}
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
+ }
+
private void setVisible(final boolean isVisible) {
if (isVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
index 03b51c6..244536d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
@@ -240,6 +240,11 @@
}
@Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+ // TODO: Car demo mode.
+ }
+
+ @Override
public boolean isPowerSave() {
// Power save is not valid for the car, so always return false.
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 7fbb176..74bd096 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -30,6 +30,7 @@
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.UserInfoController;
@@ -150,6 +151,10 @@
});
}
+ public void setQSPanel(QSPanel qsp) {
+ mMultiUserSwitch.setQsPanel(qsp);
+ }
+
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 54af684..6698d13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -127,10 +127,10 @@
mTmpInt2);
}
} else {
- Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
- getContext(), v, ContactsContract.Profile.CONTENT_URI,
- ContactsContract.QuickContact.MODE_LARGE, null);
if (mQsPanel != null) {
+ Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
+ getContext(), v, ContactsContract.Profile.CONTENT_URI,
+ ContactsContract.QuickContact.MODE_LARGE, null);
mQsPanel.getHost().startActivityDismissingKeyguard(intent);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index bb03454..583a63e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -214,15 +214,14 @@
< mContext.getResources().getDisplayMetrics().widthPixels / 2) {
createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
}
- boolean docked = mRecentsComponent.dockTopTask(dragMode, createMode, initialBounds);
+ boolean docked = mRecentsComponent.dockTopTask(dragMode, createMode, initialBounds,
+ MetricsEvent.ACTION_WINDOW_DOCK_SWIPE);
if (docked) {
mDragMode = dragMode;
if (mDragMode == DRAG_MODE_DIVIDER) {
mDivider.getView().startDragging(false /* animate */, true /* touching*/);
}
mDockWindowTouchSlopExceeded = true;
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_SWIPE);
-
return true;
}
}
@@ -250,7 +249,7 @@
mIsVertical
? mVelocityTracker.getXVelocity()
: mVelocityTracker.getYVelocity(),
- true /* avoidDismissStart */);
+ true /* avoidDismissStart */, false /* logMetrics */);
} else if (mDragMode == DRAG_MODE_RECENTS) {
mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity());
}
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 6859348..581b611 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -526,6 +526,10 @@
public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
throws RemoteException {
}
+
+ @Override
+ public void onDockSideChanged(int newDockSide) throws RemoteException {
+ }
});
} catch (RemoteException e) {
Log.e(TAG, "Failed registering docked stack exists listener", e);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index c8a2ec0..3ca0a6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -133,6 +133,7 @@
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
@@ -893,6 +894,7 @@
qsContainer.setHost(qsh);
mQSPanel = qsContainer.getQsPanel();
mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
+ mKeyguardStatusBar.setQSPanel(mQSPanel);
mHeader = qsContainer.getHeader();
initSignalCluster(mHeader);
mHeader.setActivityStarter(PhoneStatusBar.this);
@@ -1177,31 +1179,26 @@
return false;
}
- boolean initiallyDocked = WindowManagerProxy.getInstance().getDockSide()
- == WindowManager.DOCKED_INVALID;
- boolean dockedAtEnd = toggleSplitScreenMode();
- if (dockedAtEnd != initiallyDocked) {
- int logAction = dockedAtEnd ? MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS
- : MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS;
- MetricsLogger.action(mContext, logAction);
- return true;
- }
- return false;
+ toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
+ MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
+ return true;
}
};
@Override
- protected boolean toggleSplitScreenMode() {
+ protected void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
if (mRecents == null) {
- return false;
+ return;
}
int dockSide = WindowManagerProxy.getInstance().getDockSide();
if (dockSide == WindowManager.DOCKED_INVALID) {
- return mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
- ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null);
+ mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
+ ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
} else {
EventBus.getDefault().send(new UndockingTaskEvent());
- return false;
+ if (metricsUndockAction != -1) {
+ MetricsLogger.action(mContext, metricsUndockAction);
+ }
}
}
@@ -3165,7 +3162,7 @@
if (DEBUG) Log.v(TAG, "onReceive: " + intent);
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- getKeyboardShortcuts().dismissKeyboardShortcutsDialog();
+ KeyboardShortcuts.dismiss();
if (isCurrentProfile(getSendingUserId())) {
int flags = CommandQueue.FLAG_EXCLUDE_NONE;
String reason = intent.getStringExtra("reason");
@@ -3595,11 +3592,10 @@
dispatchDemoCommandToView(command, args, R.id.clock);
}
if (modeChange || command.equals(COMMAND_BATTERY)) {
- dispatchDemoCommandToView(command, args, R.id.battery);
+ mBatteryController.dispatchDemoCommand(command, args);
}
if (modeChange || command.equals(COMMAND_STATUS)) {
mIconController.dispatchDemoCommand(command, args);
-
}
if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
mNetworkController.dispatchDemoCommand(command, args);
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 0ac2e7c..823af36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -139,6 +139,7 @@
filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
// listen for user / profile change.
@@ -509,7 +510,8 @@
} else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) {
updateTTY(intent);
} else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) ||
- action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
+ action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE) ||
+ action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)) {
updateQuietState();
updateManagedProfile();
} else if (action.equals(AudioManager.ACTION_HEADSET_PLUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index ea64fd8..559436b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -16,10 +16,12 @@
package com.android.systemui.statusbar.policy;
+import com.android.systemui.DemoMode;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
-public interface BatteryController {
+public interface BatteryController extends DemoMode {
/**
* Prints the current state of the {@link BatteryController} to the given {@link PrintWriter}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 24207f3..5d734c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -21,9 +21,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
+import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.util.Log;
+import com.android.systemui.DemoMode;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -43,6 +45,7 @@
private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
private final PowerManager mPowerManager;
private final Handler mHandler;
+ private final Context mContext;
protected int mLevel;
protected boolean mPluggedIn;
@@ -52,17 +55,21 @@
private boolean mTestmode = false;
public BatteryControllerImpl(Context context) {
+ mContext = context;
mHandler = new Handler();
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ registerReceiver();
+ updatePowerSave();
+ }
+
+ private void registerReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
filter.addAction(ACTION_LEVEL_TEST);
- context.registerReceiver(this, filter);
-
- updatePowerSave();
+ mContext.registerReceiver(this, filter);
}
@Override
@@ -176,4 +183,28 @@
mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave);
}
}
+
+ private boolean mDemoMode;
+
+ @Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+ if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+ mDemoMode = true;
+ mContext.unregisterReceiver(this);
+ } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+ mDemoMode = false;
+ registerReceiver();
+ updatePowerSave();
+ } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
+ String level = args.getString("level");
+ String plugged = args.getString("plugged");
+ if (level != null) {
+ mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100);
+ }
+ if (plugged != null) {
+ mPluggedIn = Boolean.parseBoolean(plugged);
+ }
+ fireBatteryLevelChanged();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index ebefdde..52fb470 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -674,6 +674,13 @@
} else if (!selfFullscreen && otherFullscreen) {
return 1;
}
+
+ if (remoteInputActive && !o.remoteInputActive) {
+ return -1;
+ } else if (!remoteInputActive && o.remoteInputActive) {
+ return 1;
+ }
+
return postTime < o.postTime ? 1
: postTime == o.postTime ? entry.key.compareTo(o.entry.key)
: -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 7c5cdfb..8b52bf6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -3799,6 +3799,7 @@
} else {
getViewTreeObserver().removeOnPreDrawListener(mShadowUpdater);
}
+ mContinuousShadowUpdate = continuousShadowUpdate;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 450001f..acef81b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -127,8 +127,7 @@
}
@Override
- protected boolean toggleSplitScreenMode() {
- return false;
+ protected void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 748ee97..5e5da74 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -36,11 +36,16 @@
super.onCreate(savedInstanceState);
if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) {
+ final String action = getIntent().getAction();
+ boolean showDemoMode = action != null && action.equals(
+ "com.android.settings.action.DEMO_MODE");
boolean showNightMode = getIntent().getBooleanExtra(
NightModeFragment.EXTRA_SHOW_NIGHT_MODE, false);
+ final PreferenceFragment fragment = showNightMode ? new NightModeFragment()
+ : showDemoMode ? new DemoModeFragment()
+ : new TunerFragment();
getFragmentManager().beginTransaction().replace(R.id.content_frame,
- showNightMode ? new NightModeFragment() : new TunerFragment(),
- TAG_TUNER).commit();
+ fragment, TAG_TUNER).commit();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
new file mode 100644
index 0000000..c65415e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.tv.pip;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View.OnFocusChangeListener;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+/**
+ * A view containing PIP controls including fullscreen, close, and media controls.
+ */
+public class PipControlButtonView extends LinearLayout {
+ private OnFocusChangeListener mFocusChangeListener;
+ private ImageView mButtonImageView;
+ private TextView mDescriptionTextView;
+ private Animator mFocusGainAnimator;
+ private Animator mFocusLoseAnimator;
+
+ private final OnFocusChangeListener mInternalFocusChangeListener =
+ new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ if (mFocusLoseAnimator.isStarted()) {
+ mFocusLoseAnimator.cancel();
+ }
+ mFocusGainAnimator.start();
+ } else {
+ if (mFocusGainAnimator.isStarted()) {
+ mFocusGainAnimator.cancel();
+ }
+ mFocusLoseAnimator.start();
+ }
+
+ if (mFocusChangeListener != null) {
+ mFocusChangeListener.onFocusChange(v, hasFocus);
+ }
+ }
+ };
+
+ public PipControlButtonView(Context context) {
+ this(context, null, 0, 0);
+ }
+
+ public PipControlButtonView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ public PipControlButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public PipControlButtonView(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ LayoutInflater inflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.tv_pip_control_button, this);
+
+ setOrientation(LinearLayout.VERTICAL);
+ setGravity(Gravity.CENTER);
+
+ mButtonImageView = (ImageView) findViewById(R.id.button);
+ mDescriptionTextView = (TextView) findViewById(R.id.desc);
+
+ int[] values = new int[] {android.R.attr.src, android.R.attr.text};
+ TypedArray typedArray =
+ context.obtainStyledAttributes(attrs, values, defStyleAttr, defStyleRes);
+
+ mButtonImageView.setImageDrawable(typedArray.getDrawable(0));
+ mDescriptionTextView.setText(typedArray.getText(1));
+
+ typedArray.recycle();
+ }
+
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+ mButtonImageView.setOnFocusChangeListener(mInternalFocusChangeListener);
+
+ mFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
+ R.anim.tv_pip_controls_text_focus_gain_animation);
+ mFocusGainAnimator.setTarget(mDescriptionTextView);
+ mFocusLoseAnimator = AnimatorInflater.loadAnimator(getContext(),
+ R.anim.tv_pip_controls_text_focus_lose_animation);
+ mFocusLoseAnimator.setTarget(mDescriptionTextView);
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener listener) {
+ mButtonImageView.setOnClickListener(listener);
+ }
+
+ @Override
+ public void setOnFocusChangeListener(OnFocusChangeListener listener) {
+ mFocusChangeListener = listener;
+ }
+
+ /**
+ * Sets the drawable for the button with the given resource id.
+ */
+ public void setImageResource(int resId) {
+ mButtonImageView.setImageResource(resId);
+ }
+
+ /**
+ * Sets the text for description the with the given resource id.
+ */
+ public void setText(int resId) {
+ mDescriptionTextView.setText(resId);
+ }
+
+ @Override
+ public boolean isFocused() {
+ return mButtonImageView.isFocused();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
index 3f87611..d15799c 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
@@ -57,13 +57,9 @@
final PipManager mPipManager = PipManager.getInstance();
Listener mListener;
- View mFullButtonView;
- View mFullDescriptionView;
- View mPlayPauseView;
- ImageView mPlayPauseButtonImageView;
- TextView mPlayPauseDescriptionTextView;
- View mCloseButtonView;
- View mCloseDescriptionView;
+ PipControlButtonView mFullButtonView;
+ PipControlButtonView mCloseButtonView;
+ PipControlButtonView mPlayPauseButtonView;
private boolean mHasFocus;
private OnFocusChangeListener mOnChildFocusChangeListener;
@@ -75,13 +71,20 @@
}
};
- private PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
+ private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
@Override
public void onMediaControllerChanged() {
updateMediaController();
}
};
+ private final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ onChildViewFocusChanged();
+ }
+ };
+
public PipControlsView(Context context) {
this(context, null, 0, 0);
}
@@ -108,26 +111,30 @@
public void onFinishInflate() {
super.onFinishInflate();
- mFullButtonView = findViewById(R.id.full_button);
- mFullDescriptionView = findViewById(R.id.full_desc);
+ mFullButtonView = (PipControlButtonView) findViewById(R.id.full_button);
+ mFullButtonView.setOnFocusChangeListener(mFocusChangeListener);
mFullButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPipManager.movePipToFullscreen();
}
});
- mFullButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+
+ mCloseButtonView = (PipControlButtonView) findViewById(R.id.close_button);
+ mCloseButtonView.setOnFocusChangeListener(mFocusChangeListener);
+ mCloseButtonView.setOnClickListener(new View.OnClickListener() {
@Override
- public void onFocusChange(View v, boolean hasFocus) {
- mFullDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
- onChildViewFocusChanged();
+ public void onClick(View v) {
+ mPipManager.closePip();
+ if (mListener != null) {
+ mListener.onClosed();
+ }
}
});
- mPlayPauseView = findViewById(R.id.play_pause);
- mPlayPauseButtonImageView = (ImageView) findViewById(R.id.play_pause_button);
- mPlayPauseDescriptionTextView = (TextView) findViewById(R.id.play_pause_desc);
- mPlayPauseButtonImageView.setOnClickListener(new View.OnClickListener() {
+ mPlayPauseButtonView = (PipControlButtonView) findViewById(R.id.play_pause_button);
+ mPlayPauseButtonView.setOnFocusChangeListener(mFocusChangeListener);
+ mPlayPauseButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mMediaController == null || mMediaController.getPlaybackState() == null) {
@@ -143,33 +150,6 @@
// View will be updated later in {@link mMediaControllerCallback}
}
});
- mPlayPauseButtonImageView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mPlayPauseDescriptionTextView.setVisibility(
- hasFocus ? View.VISIBLE : View.INVISIBLE);
- onChildViewFocusChanged();
- }
- });
-
- mCloseButtonView = findViewById(R.id.close_button);
- mCloseDescriptionView = findViewById(R.id.close_desc);
- mCloseButtonView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mPipManager.closePip();
- if (mListener != null) {
- mListener.onClosed();
- }
- }
- });
- mCloseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mCloseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
- onChildViewFocusChanged();
- }
- });
}
@Override
@@ -206,15 +186,15 @@
private void updatePlayPauseView() {
int state = mPipManager.getPlaybackState();
if (state == PLAYBACK_STATE_UNAVAILABLE) {
- mPlayPauseView.setVisibility(View.GONE);
+ mPlayPauseButtonView.setVisibility(View.GONE);
} else {
- mPlayPauseView.setVisibility(View.VISIBLE);
+ mPlayPauseButtonView.setVisibility(View.VISIBLE);
if (state == PLAYBACK_STATE_PLAYING) {
- mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_pause_button);
- mPlayPauseDescriptionTextView.setText(R.string.pip_pause);
+ mPlayPauseButtonView.setImageResource(R.drawable.ic_pause_white_24dp);
+ mPlayPauseButtonView.setText(R.string.pip_pause);
} else {
- mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_play_button);
- mPlayPauseDescriptionTextView.setText(R.string.pip_play);
+ mPlayPauseButtonView.setImageResource(R.drawable.ic_play_arrow_white_24dp);
+ mPlayPauseButtonView.setText(R.string.pip_play);
}
}
}
@@ -229,7 +209,7 @@
private void onChildViewFocusChanged() {
// At this moment, hasFocus() returns true although there's no focused child.
boolean hasFocus = (mFullButtonView != null && mFullButtonView.isFocused())
- || (mPlayPauseButtonImageView != null && mPlayPauseButtonImageView.isFocused())
+ || (mPlayPauseButtonView != null && mPlayPauseButtonView.isFocused())
|| (mCloseButtonView != null && mCloseButtonView.isFocused());
if (mHasFocus != hasFocus) {
mHasFocus = hasFocus;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index 854e09d..542a935 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -16,10 +16,14 @@
package com.android.systemui.tv.pip;
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
import android.app.Activity;
import android.os.Bundle;
+import android.view.View;
import com.android.systemui.R;
+import com.android.systemui.Interpolators;
/**
* Activity to show the PIP menu to control PIP.
@@ -29,7 +33,9 @@
private final PipManager mPipManager = PipManager.getInstance();
- private PipControlsView mPipControlsView;
+ private Animator mFadeInAnimation;
+ private Animator mFadeOutAnimation;
+ private View mPipControlsView;
private boolean mRestorePipSizeWhenClose;
@Override
@@ -38,8 +44,14 @@
setContentView(R.layout.tv_pip_menu);
mPipManager.addListener(this);
- mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
mRestorePipSizeWhenClose = true;
+ mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
+ mFadeInAnimation = AnimatorInflater.loadAnimator(
+ this, R.anim.tv_pip_menu_fade_in_animation);
+ mFadeInAnimation.setTarget(mPipControlsView);
+ mFadeOutAnimation = AnimatorInflater.loadAnimator(
+ this, R.anim.tv_pip_menu_fade_out_animation);
+ mFadeOutAnimation.setTarget(mPipControlsView);
}
private void restorePipAndFinish() {
@@ -51,8 +63,15 @@
}
@Override
+ public void onResume() {
+ super.onResume();
+ mFadeInAnimation.start();
+ }
+
+ @Override
public void onPause() {
super.onPause();
+ mFadeOutAnimation.start();
restorePipAndFinish();
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
index 8b8c105..9c806f7 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
@@ -72,28 +72,20 @@
super.onFinishInflate();
int buttonsFocusGainAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_gain_animation;
- int textFocusGainAnim = R.anim.tv_pip_controls_text_in_recents_focus_gain_animation;
mFocusGainAnimatorSet = new AnimatorSet();
mFocusGainAnimatorSet.playTogether(
loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_gain_animation),
loadAnimator(mFullButtonView,buttonsFocusGainAnim),
- loadAnimator(mPlayPauseButtonImageView, buttonsFocusGainAnim),
- loadAnimator(mCloseButtonView, buttonsFocusGainAnim),
- loadAnimator(mFullDescriptionView, textFocusGainAnim),
- loadAnimator(mPlayPauseDescriptionTextView, textFocusGainAnim),
- loadAnimator(mCloseDescriptionView, textFocusGainAnim));
+ loadAnimator(mPlayPauseButtonView, buttonsFocusGainAnim),
+ loadAnimator(mCloseButtonView, buttonsFocusGainAnim));
int buttonsFocusLoseAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_lose_animation;
- int textFocusLoseAnim = R.anim.tv_pip_controls_text_in_recents_focus_lose_animation;
mFocusLoseAnimatorSet = new AnimatorSet();
mFocusLoseAnimatorSet.playTogether(
loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_lose_animation),
loadAnimator(mFullButtonView, buttonsFocusLoseAnim),
- loadAnimator(mPlayPauseButtonImageView, buttonsFocusLoseAnim),
- loadAnimator(mCloseButtonView, buttonsFocusLoseAnim),
- loadAnimator(mFullDescriptionView, textFocusLoseAnim),
- loadAnimator(mPlayPauseDescriptionTextView, textFocusLoseAnim),
- loadAnimator(mCloseDescriptionView, textFocusLoseAnim));
+ loadAnimator(mPlayPauseButtonView, buttonsFocusLoseAnim),
+ loadAnimator(mCloseButtonView, buttonsFocusLoseAnim));
Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
int pipControlsMarginTop = getContext().getResources().getDimensionPixelSize(
@@ -142,11 +134,8 @@
requestFocus();
setTranslationY(0);
setScaleXY(mFullButtonView, 1);
- setScaleXY(mPlayPauseButtonImageView, 1);
+ setScaleXY(mPlayPauseButtonView, 1);
setScaleXY(mCloseButtonView, 1);
- mFullDescriptionView.setAlpha(1);
- mPlayPauseDescriptionTextView.setAlpha(1);
- mCloseDescriptionView.setAlpha(1);
}
private void setScaleXY(View view, float scale) {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
index 47cd8e5..8567625 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -16,8 +16,6 @@
package com.android.systemui.tv.pip;
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorSet;
import android.content.Context;
import android.graphics.PixelFormat;
import android.util.Log;
@@ -134,6 +132,7 @@
* @param allowRecentsFocusable {@code true} if Recents can have focus. (i.e. Has a recent task)
*/
public void requestFocus(boolean allowRecentsFocusable) {
+ mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
if (!mIsRecentsShown || mIsPipFocusedInRecent) {
return;
}
@@ -143,7 +142,6 @@
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
mPipControlsView.requestFocus();
mPipControlsView.startFocusGainAnimation();
- mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
}
/**
diff --git a/preloaded-classes b/preloaded-classes
index be645d2..d854769 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -12,6 +12,7 @@
[Landroid.animation.Keyframe;
[Landroid.animation.PropertyValuesHolder;
[Landroid.app.LoaderManagerImpl;
+[Landroid.app.Notification$Action;
[Landroid.content.ContentProviderResult;
[Landroid.content.ContentValues;
[Landroid.content.Intent;
@@ -29,7 +30,6 @@
[Landroid.content.res.Configuration;
[Landroid.content.res.StringBlock;
[Landroid.content.res.XmlBlock;
-[Landroid.database.Cursor;
[Landroid.database.CursorWindow;
[Landroid.database.sqlite.SQLiteConnection$Operation;
[Landroid.database.sqlite.SQLiteConnectionPool$AcquiredConnectionStatus;
@@ -54,7 +54,6 @@
[Landroid.graphics.drawable.GradientDrawable$Orientation;
[Landroid.graphics.drawable.LayerDrawable$ChildDrawable;
[Landroid.graphics.drawable.RippleForeground;
-[Landroid.hardware.display.WifiDisplay;
[Landroid.hardware.soundtrigger.SoundTrigger$ConfidenceLevel;
[Landroid.hardware.soundtrigger.SoundTrigger$Keyphrase;
[Landroid.hardware.soundtrigger.SoundTrigger$KeyphraseRecognitionExtra;
@@ -83,6 +82,10 @@
[Landroid.icu.util.ULocale$Category;
[Landroid.icu.util.ULocale;
[Landroid.media.AudioGain;
+[Landroid.media.MediaCodecInfo$CodecCapabilities;
+[Landroid.media.MediaCodecInfo$CodecProfileLevel;
+[Landroid.media.MediaCodecInfo$Feature;
+[Landroid.media.MediaCodecInfo;
[Landroid.net.Network;
[Landroid.net.NetworkInfo$DetailedState;
[Landroid.net.NetworkInfo$State;
@@ -109,7 +112,6 @@
[Landroid.text.method.TextKeyListener;
[Landroid.text.style.AlignmentSpan;
[Landroid.text.style.CharacterStyle;
-[Landroid.text.style.ClickableSpan;
[Landroid.text.style.LeadingMarginSpan;
[Landroid.text.style.LineBackgroundSpan;
[Landroid.text.style.LineHeightSpan;
@@ -122,12 +124,11 @@
[Landroid.text.style.URLSpan;
[Landroid.text.style.WrapTogetherSpan;
[Landroid.util.LongSparseArray;
-[Landroid.util.Pair;
+[Landroid.util.Range;
[Landroid.util.Rational;
[Landroid.view.Choreographer$CallbackQueue;
[Landroid.view.Display$ColorTransform;
[Landroid.view.Display$Mode;
-[Landroid.view.Display;
[Landroid.view.HandlerActionQueue$HandlerAction;
[Landroid.view.MenuItem;
[Landroid.view.View;
@@ -198,11 +199,13 @@
[Ljava.text.DateFormat$Field;
[Ljava.text.Normalizer$Form;
[Ljava.util.ArrayList;
+[Ljava.util.Comparators$NaturalOrderComparator;
[Ljava.util.Enumeration;
[Ljava.util.Formatter$Flags;
[Ljava.util.Formatter$FormatString;
[Ljava.util.HashMap$HashMapEntry;
[Ljava.util.Hashtable$HashtableEntry;
+[Ljava.util.List;
[Ljava.util.Locale$Category;
[Ljava.util.Locale;
[Ljava.util.Map$Entry;
@@ -216,11 +219,8 @@
[Ljava.util.regex.Pattern;
[Ljavax.crypto.Cipher$InitType;
[Ljavax.crypto.Cipher$NeedToSet;
-[Ljavax.microedition.khronos.egl.EGLConfig;
[Ljavax.net.ssl.KeyManager;
-[Ljavax.net.ssl.SSLSession;
[Ljavax.net.ssl.TrustManager;
-[Ljavax.security.auth.x500.X500Principal;
[Ljavax.security.cert.X509Certificate;
[Llibcore.io.ClassPathURLStreamHandler;
[Llibcore.reflect.AnnotationMember$DefaultValues;
@@ -307,12 +307,10 @@
android.animation.PathKeyframes$1
android.animation.PathKeyframes$2
android.animation.PathKeyframes$FloatKeyframesBase
-android.animation.PathKeyframes$IntKeyframesBase
android.animation.PathKeyframes$SimpleKeyframes
android.animation.PropertyValuesHolder
android.animation.PropertyValuesHolder$FloatPropertyValuesHolder
android.animation.PropertyValuesHolder$IntPropertyValuesHolder
-android.animation.PropertyValuesHolder$PropertyValues
android.animation.RectEvaluator
android.animation.StateListAnimator
android.animation.StateListAnimator$1
@@ -328,7 +326,6 @@
android.app.Activity$HostCallbacks
android.app.ActivityManager
android.app.ActivityManager$MemoryInfo
-android.app.ActivityManager$RecentTaskInfo
android.app.ActivityManager$RunningAppProcessInfo
android.app.ActivityManager$RunningAppProcessInfo$1
android.app.ActivityManager$StackId
@@ -348,7 +345,6 @@
android.app.ActivityThread$ApplicationThread
android.app.ActivityThread$BindServiceData
android.app.ActivityThread$ContextCleanupInfo
-android.app.ActivityThread$CreateBackupAgentData
android.app.ActivityThread$CreateServiceData
android.app.ActivityThread$DropBoxReporter
android.app.ActivityThread$EventLoggingReporter
@@ -381,7 +377,7 @@
android.app.ContextImpl
android.app.ContextImpl$ApplicationContentResolver
android.app.Dialog
-android.app.Dialog$1
+android.app.Dialog$-void__init__android_content_Context_context_int_themeResId_boolean_createContextThemeWrapper_LambdaImpl0
android.app.Dialog$ListenersHandler
android.app.DialogFragment
android.app.DownloadManager
@@ -402,8 +398,6 @@
android.app.IAlarmManager$Stub
android.app.IAlarmManager$Stub$Proxy
android.app.IApplicationThread
-android.app.IBackupAgent
-android.app.IBackupAgent$Stub
android.app.IInstrumentationWatcher
android.app.IInstrumentationWatcher$Stub
android.app.INotificationManager
@@ -415,6 +409,9 @@
android.app.ITransientNotification$Stub
android.app.IUiAutomationConnection
android.app.IUiAutomationConnection$Stub
+android.app.IUiModeManager
+android.app.IUiModeManager$Stub
+android.app.IUiModeManager$Stub$Proxy
android.app.Instrumentation
android.app.IntentReceiverLeaked
android.app.IntentService
@@ -437,16 +434,21 @@
android.app.Notification
android.app.Notification$1
android.app.Notification$Action
+android.app.Notification$Action$1
android.app.Notification$BigTextStyle
android.app.Notification$Builder
+android.app.Notification$BuilderRemoteViews
android.app.Notification$Style
android.app.NotificationManager
+android.app.OnActivityPausedListener
android.app.PendingIntent
android.app.PendingIntent$1
android.app.PendingIntent$CanceledException
android.app.QueuedWork
android.app.ReceiverRestrictedContext
android.app.ResourcesManager
+android.app.ResourcesManager$1
+android.app.ResourcesManager$ActivityResources
android.app.ResultInfo
android.app.ResultInfo$1
android.app.Service
@@ -530,11 +532,15 @@
android.app.SystemServiceRegistry$69
android.app.SystemServiceRegistry$7
android.app.SystemServiceRegistry$70
+android.app.SystemServiceRegistry$71
+android.app.SystemServiceRegistry$72
+android.app.SystemServiceRegistry$73
+android.app.SystemServiceRegistry$74
android.app.SystemServiceRegistry$8
android.app.SystemServiceRegistry$9
android.app.SystemServiceRegistry$CachedServiceFetcher
android.app.SystemServiceRegistry$ServiceFetcher
-android.app.SystemServiceRegistry$StaticOuterContextServiceFetcher
+android.app.SystemServiceRegistry$StaticApplicationContextServiceFetcher
android.app.SystemServiceRegistry$StaticServiceFetcher
android.app.UiModeManager
android.app.WallpaperManager
@@ -542,10 +548,9 @@
android.app.admin.IDevicePolicyManager
android.app.admin.IDevicePolicyManager$Stub
android.app.admin.IDevicePolicyManager$Stub$Proxy
-android.app.backup.BackupAgent
-android.app.backup.BackupAgent$BackupServiceBinder
-android.app.backup.BackupAgent$SharedPrefsSynchronizer
-android.app.backup.BackupAgentHelper
+android.app.admin.SecurityLog
+android.app.admin.SecurityLog$SecurityEvent
+android.app.admin.SecurityLog$SecurityEvent$1
android.app.backup.BackupDataInput
android.app.backup.BackupDataInput$EntityHeader
android.app.backup.BackupDataOutput
@@ -554,9 +559,6 @@
android.app.backup.FileBackupHelperBase
android.app.backup.FullBackup
android.app.backup.FullBackupDataOutput
-android.app.backup.IBackupManager
-android.app.backup.IBackupManager$Stub
-android.app.backup.IBackupManager$Stub$Proxy
android.app.job.JobScheduler
android.app.trust.ITrustManager
android.app.trust.ITrustManager$Stub
@@ -566,9 +568,6 @@
android.app.usage.UsageStatsManager
android.appwidget.AppWidgetManager
android.appwidget.AppWidgetProvider
-android.auditing.SecurityLog
-android.auditing.SecurityLog$SecurityEvent
-android.auditing.SecurityLog$SecurityEvent$1
android.bluetooth.BluetoothAdapter
android.bluetooth.BluetoothAdapter$1
android.bluetooth.BluetoothManager
@@ -585,6 +584,7 @@
android.content.ActivityNotFoundException
android.content.BroadcastReceiver
android.content.BroadcastReceiver$PendingResult
+android.content.BroadcastReceiver$PendingResult$1
android.content.ClipData
android.content.ClipData$1
android.content.ClipData$Item
@@ -600,7 +600,6 @@
android.content.ContentProviderClient
android.content.ContentProviderNative
android.content.ContentProviderOperation
-android.content.ContentProviderOperation$Builder
android.content.ContentProviderProxy
android.content.ContentProviderResult
android.content.ContentResolver
@@ -637,7 +636,6 @@
android.content.IntentSender
android.content.IntentSender$SendIntentException
android.content.OperationApplicationException
-android.content.PeriodicSync
android.content.RestrictionsManager
android.content.ServiceConnection
android.content.SharedPreferences
@@ -646,7 +644,6 @@
android.content.SyncContext
android.content.SyncRequest
android.content.SyncRequest$1
-android.content.SyncRequest$Builder
android.content.SyncResult
android.content.SyncResult$1
android.content.SyncStats
@@ -693,6 +690,7 @@
android.content.pm.ResolveInfo$1
android.content.pm.ServiceInfo
android.content.pm.ServiceInfo$1
+android.content.pm.ShortcutManager
android.content.pm.Signature
android.content.pm.Signature$1
android.content.pm.UserInfo
@@ -721,6 +719,8 @@
android.content.res.Resources$NotFoundException
android.content.res.Resources$Theme
android.content.res.Resources$ThemeKey
+android.content.res.ResourcesImpl
+android.content.res.ResourcesImpl$ThemeImpl
android.content.res.ResourcesKey
android.content.res.StringBlock
android.content.res.StringBlock$StyleIDs
@@ -762,7 +762,6 @@
android.database.IContentObserver$Stub$Proxy
android.database.MatrixCursor
android.database.MatrixCursor$RowBuilder
-android.database.MergeCursor
android.database.Observable
android.database.SQLException
android.database.sqlite.DatabaseObjectNotClosedException
@@ -775,7 +774,6 @@
android.database.sqlite.SQLiteConnectionPool
android.database.sqlite.SQLiteConnectionPool$AcquiredConnectionStatus
android.database.sqlite.SQLiteConnectionPool$ConnectionWaiter
-android.database.sqlite.SQLiteConstraintException
android.database.sqlite.SQLiteCursor
android.database.sqlite.SQLiteCursorDriver
android.database.sqlite.SQLiteCustomFunction
@@ -807,7 +805,6 @@
android.ddm.DdmHandleThread
android.ddm.DdmHandleViewDebug
android.ddm.DdmRegister
-android.graphics.AvoidXfermode
android.graphics.Bitmap
android.graphics.Bitmap$1
android.graphics.Bitmap$CompressFormat
@@ -820,10 +817,10 @@
android.graphics.Camera
android.graphics.Canvas
android.graphics.Canvas$EdgeType
+android.graphics.Canvas$NoImagePreloadHolder
android.graphics.CanvasProperty
android.graphics.Color
android.graphics.ColorFilter
-android.graphics.ColorMatrix
android.graphics.ColorMatrixColorFilter
android.graphics.ComposePathEffect
android.graphics.ComposeShader
@@ -859,6 +856,7 @@
android.graphics.Paint$FontMetrics
android.graphics.Paint$FontMetricsInt
android.graphics.Paint$Join
+android.graphics.Paint$NoImagePreloadHolder
android.graphics.Paint$Style
android.graphics.PaintFlagsDrawFilter
android.graphics.Path
@@ -869,7 +867,6 @@
android.graphics.PathMeasure
android.graphics.Picture
android.graphics.PixelFormat
-android.graphics.PixelXorXfermode
android.graphics.Point
android.graphics.Point$1
android.graphics.PointF
@@ -903,11 +900,14 @@
android.graphics.drawable.Animatable2
android.graphics.drawable.AnimatedStateListDrawable
android.graphics.drawable.AnimatedStateListDrawable$AnimatedStateListState
+android.graphics.drawable.AnimatedStateListDrawable$Transition
android.graphics.drawable.AnimatedVectorDrawable
android.graphics.drawable.AnimatedVectorDrawable$1
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState$PendingAnimator
+android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimator
android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT
+android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorUI
android.graphics.drawable.AnimationDrawable
android.graphics.drawable.AnimationDrawable$AnimationState
android.graphics.drawable.BitmapDrawable
@@ -976,12 +976,14 @@
android.hardware.Camera$Face
android.hardware.ConsumerIrManager
android.hardware.Sensor
+android.hardware.SensorEvent
android.hardware.SensorEventListener
android.hardware.SensorManager
android.hardware.SerialManager
android.hardware.SerialPort
android.hardware.SystemSensorManager
android.hardware.SystemSensorManager$BaseEventQueue
+android.hardware.SystemSensorManager$SensorEventQueue
android.hardware.camera2.CameraCharacteristics$Key
android.hardware.camera2.CameraManager
android.hardware.camera2.CaptureRequest$Key
@@ -1000,12 +1002,6 @@
android.hardware.display.IDisplayManager$Stub$Proxy
android.hardware.display.IDisplayManagerCallback
android.hardware.display.IDisplayManagerCallback$Stub
-android.hardware.display.WifiDisplay
-android.hardware.display.WifiDisplay$1
-android.hardware.display.WifiDisplaySessionInfo
-android.hardware.display.WifiDisplaySessionInfo$1
-android.hardware.display.WifiDisplayStatus
-android.hardware.display.WifiDisplayStatus$1
android.hardware.fingerprint.FingerprintManager
android.hardware.hdmi.HdmiControlManager
android.hardware.input.IInputDevicesChangedListener
@@ -1021,6 +1017,10 @@
# android.hardware.location.ActivityRecognitionHardware
# android.hardware.location.IActivityRecognitionHardware
# android.hardware.location.IActivityRecognitionHardware$Stub
+android.hardware.location.ContextHubManager
+android.hardware.location.ContextHubService
+android.hardware.location.IContextHubService
+android.hardware.location.IContextHubService$Stub
android.hardware.radio.RadioManager
android.hardware.radio.RadioManager$AmBandConfig
android.hardware.radio.RadioManager$AmBandConfig$1
@@ -1046,6 +1046,7 @@
android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel
android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel$1
android.hardware.soundtrigger.SoundTrigger$GenericRecognitionEvent
+android.hardware.soundtrigger.SoundTrigger$GenericRecognitionEvent$1
android.hardware.soundtrigger.SoundTrigger$GenericSoundModel
android.hardware.soundtrigger.SoundTrigger$Keyphrase
android.hardware.soundtrigger.SoundTrigger$Keyphrase$1
@@ -1070,7 +1071,6 @@
android.hardware.usb.IUsbManager$Stub$Proxy
android.hardware.usb.UsbDevice
android.hardware.usb.UsbDeviceConnection
-android.hardware.usb.UsbInterface
android.hardware.usb.UsbManager
android.hardware.usb.UsbRequest
android.icu.impl.BMPSet
@@ -1396,6 +1396,7 @@
android.media.AudioDevicePort
android.media.AudioDevicePortConfig
android.media.AudioFormat
+android.media.AudioFormat$1
android.media.AudioGain
android.media.AudioGainConfig
android.media.AudioHandle
@@ -1412,8 +1413,6 @@
android.media.AudioPortConfig
android.media.AudioPortEventHandler
android.media.AudioRecord
-android.media.AudioRoutesInfo
-android.media.AudioRoutesInfo$1
android.media.AudioRouting
android.media.AudioSystem
android.media.AudioTimestamp
@@ -1425,21 +1424,13 @@
android.media.ExifInterface
android.media.IAudioFocusDispatcher
android.media.IAudioFocusDispatcher$Stub
-android.media.IAudioRoutesObserver
-android.media.IAudioRoutesObserver$Stub
android.media.IAudioService
android.media.IAudioService$Stub
android.media.IAudioService$Stub$Proxy
android.media.IMediaHTTPConnection
android.media.IMediaHTTPConnection$Stub
-android.media.IMediaRouterClient
-android.media.IMediaRouterClient$Stub
-android.media.IMediaRouterService
-android.media.IMediaRouterService$Stub
android.media.IRecordingConfigDispatcher
android.media.IRecordingConfigDispatcher$Stub
-android.media.IRemoteVolumeObserver
-android.media.IRemoteVolumeObserver$Stub
android.media.Image
android.media.ImageReader
android.media.ImageReader$SurfaceImage
@@ -1447,10 +1438,18 @@
android.media.ImageWriter$WriterSurfaceImage
android.media.JetPlayer
android.media.MediaCodec
+android.media.MediaCodecInfo
+android.media.MediaCodecInfo$AudioCapabilities
+android.media.MediaCodecInfo$CodecCapabilities
+android.media.MediaCodecInfo$CodecProfileLevel
+android.media.MediaCodecInfo$EncoderCapabilities
+android.media.MediaCodecInfo$Feature
+android.media.MediaCodecInfo$VideoCapabilities
android.media.MediaCodecList
android.media.MediaCrypto
android.media.MediaDrm
android.media.MediaExtractor
+android.media.MediaFormat
android.media.MediaHTTPConnection
android.media.MediaMetadataRetriever
android.media.MediaMuxer
@@ -1461,17 +1460,6 @@
android.media.MediaPlayer$OnSeekCompleteListener
android.media.MediaRecorder
android.media.MediaRouter
-android.media.MediaRouter$Callback
-android.media.MediaRouter$RouteCategory
-android.media.MediaRouter$RouteInfo
-android.media.MediaRouter$RouteInfo$1
-android.media.MediaRouter$Static
-android.media.MediaRouter$Static$1
-android.media.MediaRouter$Static$Client
-android.media.MediaRouter$VolumeChangeReceiver
-android.media.MediaRouter$WifiDisplayStatusChangedReceiver
-android.media.MediaRouterClientState
-android.media.MediaRouterClientState$1
android.media.MediaScanner
android.media.MediaSync
android.media.PlaybackParams
@@ -1479,9 +1467,10 @@
android.media.RemoteDisplay
android.media.ResampleInputStream
android.media.SubtitleController$Listener
-android.media.ThumbnailUtils
android.media.ToneGenerator
-android.media.audiofx.AcousticEchoCanceler
+android.media.Utils
+android.media.Utils$1
+android.media.Utils$2
android.media.audiofx.AudioEffect
android.media.audiopolicy.AudioMix
android.media.audiopolicy.AudioMixingRule
@@ -1504,13 +1493,13 @@
android.net.ConnectivityManager
android.net.ConnectivityManager$CallbackHandler
android.net.ConnectivityManager$NetworkCallback
+android.net.ConnectivityThread
android.net.Credentials
-android.net.DhcpResults
-android.net.DhcpResults$1
android.net.EthernetManager
android.net.IConnectivityManager
android.net.IConnectivityManager$Stub
android.net.IConnectivityManager$Stub$Proxy
+android.net.INetworkPolicyManager
android.net.IpPrefix
android.net.IpPrefix$1
android.net.LinkAddress
@@ -1545,8 +1534,6 @@
android.net.SSLCertificateSocketFactory
android.net.SSLCertificateSocketFactory$1
android.net.SSLSessionCache
-android.net.StaticIpConfiguration
-android.net.StaticIpConfiguration$1
android.net.TrafficStats
android.net.Uri
android.net.Uri$1
@@ -1584,10 +1571,16 @@
android.nfc.INfcAdapter$Stub$Proxy
android.nfc.INfcCardEmulation
android.nfc.INfcCardEmulation$Stub
+android.nfc.INfcCardEmulation$Stub$Proxy
android.nfc.INfcFCardEmulation
android.nfc.INfcFCardEmulation$Stub
+android.nfc.INfcFCardEmulation$Stub$Proxy
android.nfc.INfcTag
android.nfc.INfcTag$Stub
+android.nfc.INfcTag$Stub$Proxy
+android.nfc.NfcActivityManager
+android.nfc.NfcAdapter
+android.nfc.NfcAdapter$1
android.nfc.NfcManager
android.opengl.EGL14
android.opengl.EGLConfig
@@ -1631,9 +1624,8 @@
android.os.CancellationSignal$OnCancelListener
android.os.CancellationSignal$Transport
android.os.ConditionVariable
-android.os.CpuUsageInfo
-android.os.CpuUsageInfo$1
android.os.DeadObjectException
+android.os.DeadSystemException
android.os.Debug
android.os.Debug$MemoryInfo
android.os.Debug$MemoryInfo$1
@@ -1665,6 +1657,8 @@
android.os.IUserManager
android.os.IUserManager$Stub
android.os.IUserManager$Stub$Proxy
+android.os.IVibratorService
+android.os.IVibratorService$Stub
android.os.Looper
android.os.MemoryFile
android.os.Message
@@ -1679,10 +1673,13 @@
android.os.ParcelFileDescriptor
android.os.ParcelFileDescriptor$1
android.os.ParcelFileDescriptor$AutoCloseInputStream
+android.os.ParcelFileDescriptor$AutoCloseOutputStream
android.os.ParcelUuid
android.os.Parcelable
android.os.Parcelable$ClassLoaderCreator
android.os.Parcelable$Creator
+android.os.ParcelableParcel
+android.os.ParcelableParcel$1
android.os.PatternMatcher
android.os.PatternMatcher$1
android.os.PersistableBundle
@@ -1691,6 +1688,7 @@
android.os.PowerManager$WakeLock
android.os.PowerManager$WakeLock$1
android.os.Process
+android.os.RecoverySystem
android.os.RemoteException
android.os.ResultReceiver
android.os.SELinux
@@ -1726,24 +1724,26 @@
android.os.StrictMode$VmPolicy$Builder
android.os.SystemClock
android.os.SystemProperties
+android.os.SystemVibrator
android.os.Trace
android.os.Trace$1
-android.os.TransactionTooLargeException
android.os.UEventObserver
android.os.UserHandle
android.os.UserHandle$1
android.os.UserManager
android.os.Vibrator
android.os.ZygoteStartFailedEx
+android.os.health.SystemHealthManager
android.os.storage.IMountService
android.os.storage.IMountService$Stub
android.os.storage.IMountService$Stub$Proxy
+android.os.storage.IObbActionListener
+android.os.storage.IObbActionListener$Stub
android.os.storage.StorageManager
+android.os.storage.StorageManager$ObbActionListener
android.os.storage.StorageVolume
android.os.storage.StorageVolume$1
-android.preference.Preference$OnPreferenceChangeListener
android.preference.PreferenceActivity
-android.preference.PreferenceFragment
android.preference.PreferenceFragment$OnPreferenceStartFragmentCallback
android.preference.PreferenceManager
android.preference.PreferenceManager$OnPreferenceTreeClickListener
@@ -1836,7 +1836,6 @@
android.system.UnixSocketAddress
android.telecom.TelecomManager
android.telephony.CarrierConfigManager
-android.telephony.PhoneNumberUtils
android.telephony.Rlog
android.telephony.SubscriptionManager
android.telephony.TelephonyManager
@@ -1852,12 +1851,15 @@
android.text.GetChars
android.text.GraphicsOperations
android.text.Html
+android.text.Html$HtmlParser
+android.text.HtmlToSpannedConverter
android.text.Hyphenator
android.text.InputFilter
android.text.InputType
android.text.Layout
android.text.Layout$Alignment
android.text.Layout$Directions
+android.text.Layout$Ellipsizer
android.text.MeasuredText
android.text.NoCopySpan
android.text.NoCopySpan$Concrete
@@ -1916,7 +1918,6 @@
android.text.method.SingleLineTransformationMethod
android.text.method.TextKeyListener
android.text.method.TextKeyListener$Capitalize
-android.text.method.Touch
android.text.method.TransformationMethod
android.text.method.TransformationMethod2
android.text.style.AlignmentSpan
@@ -1937,6 +1938,7 @@
android.text.style.StyleSpan
android.text.style.SuggestionSpan
android.text.style.TabStopSpan
+android.text.style.TextAppearanceSpan
android.text.style.URLSpan
android.text.style.UnderlineSpan
android.text.style.UpdateAppearance
@@ -1985,7 +1987,6 @@
android.util.EventLog$Event
android.util.FloatProperty
android.util.IntProperty
-android.util.JsonReader
android.util.LocaleList
android.util.LocaleList$1
android.util.Log
@@ -1993,7 +1994,6 @@
android.util.Log$ImmediateLogWriter
android.util.Log$TerribleFailureHandler
android.util.LogPrinter
-android.util.LongArray
android.util.LongSparseArray
android.util.LongSparseLongArray
android.util.LruCache
@@ -2006,15 +2006,16 @@
android.util.Pair
android.util.PathParser
android.util.PathParser$PathData
-android.util.Patterns
android.util.Pools$Pool
android.util.Pools$SimplePool
android.util.Pools$SynchronizedPool
android.util.Printer
android.util.Property
+android.util.Range
android.util.Rational
android.util.Singleton
android.util.Size
+android.util.SizeF
android.util.Slog
android.util.SparseArray
android.util.SparseBooleanArray
@@ -2031,6 +2032,7 @@
android.view.AbsSavedState$2
android.view.ActionMode
android.view.ActionMode$Callback
+android.view.ActionMode$Callback2
android.view.ActionProvider
android.view.ActionProvider$SubUiVisibilityListener
android.view.Choreographer
@@ -2135,7 +2137,6 @@
android.view.RenderNode
android.view.RenderNodeAnimator
android.view.RenderNodeAnimator$1
-android.view.RenderNodeAnimatorSetHelper
android.view.SearchEvent
android.view.SoundEffectConstants
android.view.SubMenu
@@ -2151,6 +2152,7 @@
android.view.SurfaceSession
android.view.SurfaceView
android.view.TextureView
+android.view.TextureView$SurfaceTextureListener
android.view.ThreadedRenderer
android.view.ThreadedRenderer$HardwareDrawCallbacks
android.view.ThreadedRenderer$ProcessInitializer
@@ -2174,6 +2176,7 @@
android.view.View$AttachInfo$Callbacks
android.view.View$BaseSavedState
android.view.View$BaseSavedState$1
+android.view.View$CheckForLongPress
android.view.View$CheckForTap
android.view.View$ForegroundInfo
android.view.View$ListenerInfo
@@ -2258,10 +2261,10 @@
android.view.WindowCallbacks
android.view.WindowContentFrameStats
android.view.WindowContentFrameStats$1
-android.view.WindowId
android.view.WindowInsets
android.view.WindowLeaked
android.view.WindowManager
+android.view.WindowManager$BadTokenException
android.view.WindowManager$LayoutParams
android.view.WindowManager$LayoutParams$1
android.view.WindowManagerGlobal
@@ -2280,6 +2283,7 @@
android.view.accessibility.AccessibilityRecord
android.view.accessibility.CaptioningManager
android.view.accessibility.CaptioningManager$1
+android.view.accessibility.CaptioningManager$CaptionStyle
android.view.accessibility.CaptioningManager$CaptioningChangeListener
android.view.accessibility.CaptioningManager$MyContentObserver
android.view.accessibility.IAccessibilityManager
@@ -2295,6 +2299,7 @@
android.view.animation.Animation$2
android.view.animation.Animation$3
android.view.animation.Animation$AnimationListener
+android.view.animation.Animation$Description
android.view.animation.AnimationSet
android.view.animation.AnimationUtils
android.view.animation.BaseInterpolator
@@ -2316,6 +2321,7 @@
android.view.inputmethod.ExtractedText
android.view.inputmethod.ExtractedText$1
android.view.inputmethod.InputConnection
+android.view.inputmethod.InputConnectionInspector
android.view.inputmethod.InputMethodManager
android.view.inputmethod.InputMethodManager$1
android.view.inputmethod.InputMethodManager$ControlledInputConnectionWrapper
@@ -2323,15 +2329,17 @@
android.view.inputmethod.InputMethodManager$H
android.view.inputmethod.InputMethodManager$ImeInputEventSender
android.view.inputmethod.InputMethodManager$PendingEvent
-android.view.inputmethod.InputMethodSubtype
android.view.textservice.SpellCheckerSession$SpellCheckerSessionListener
android.view.textservice.SpellCheckerSubtype
android.view.textservice.SpellCheckerSubtype$1
android.view.textservice.TextServicesManager
+android.webkit.IWebViewUpdateService
+android.webkit.IWebViewUpdateService$Stub
android.webkit.MimeTypeMap
android.webkit.URLUtil
android.webkit.WebSettings
android.webkit.WebView
+android.webkit.WebViewClient
android.webkit.WebViewFactory
android.webkit.WebViewFactory$MissingWebViewPackageException
android.widget.AbsListView
@@ -2348,6 +2356,7 @@
android.widget.AbsListView$WindowRunnnable
android.widget.AbsSeekBar
android.widget.AbsSpinner
+android.widget.AbsSpinner$RecycleBin
android.widget.AbsoluteLayout
android.widget.ActionMenuPresenter
android.widget.ActionMenuPresenter$1
@@ -2362,13 +2371,9 @@
android.widget.AdapterView
android.widget.AdapterView$AdapterDataSetObserver
android.widget.AdapterView$OnItemClickListener
-android.widget.AdapterView$OnItemLongClickListener
android.widget.AdapterView$OnItemSelectedListener
android.widget.ArrayAdapter
android.widget.AutoCompleteTextView
-android.widget.AutoCompleteTextView$DropDownItemClickListener
-android.widget.AutoCompleteTextView$MyWatcher
-android.widget.AutoCompleteTextView$PassThroughClickListener
android.widget.BaseAdapter
android.widget.Button
android.widget.CheckBox
@@ -2381,15 +2386,17 @@
android.widget.Editor
android.widget.Editor$1
android.widget.Editor$2
-android.widget.Editor$3
android.widget.Editor$Blink
android.widget.Editor$CursorAnchorInfoNotifier
+android.widget.Editor$CursorController
android.widget.Editor$EditOperation
android.widget.Editor$EditOperation$1
android.widget.Editor$InputContentType
android.widget.Editor$InputMethodState
+android.widget.Editor$InsertionPointCursorController
android.widget.Editor$PositionListener
android.widget.Editor$ProcessTextIntentActionsHandler
+android.widget.Editor$SelectionModifierCursorController
android.widget.Editor$SpanController
android.widget.Editor$SuggestionHelper
android.widget.Editor$SuggestionHelper$SuggestionSpanComparator
@@ -2439,6 +2446,19 @@
android.widget.RelativeLayout$DependencyGraph$Node
android.widget.RelativeLayout$LayoutParams
android.widget.RemoteViews
+android.widget.RemoteViews$1
+android.widget.RemoteViews$2
+android.widget.RemoteViews$3
+android.widget.RemoteViews$Action
+android.widget.RemoteViews$ActionException
+android.widget.RemoteViews$BitmapCache
+android.widget.RemoteViews$LayoutParamAction
+android.widget.RemoteViews$MemoryUsageCounter
+android.widget.RemoteViews$MutablePair
+android.widget.RemoteViews$OnClickHandler
+android.widget.RemoteViews$ReflectionAction
+android.widget.RemoteViews$RuntimeAction
+android.widget.RemoteViews$SetDrawableParameters
android.widget.RemoteViewsAdapter$RemoteAdapterConnectionCallback
android.widget.RtlSpacingHelper
android.widget.ScrollBarDrawable
@@ -2451,7 +2471,10 @@
android.widget.SpellChecker
android.widget.SpellChecker$SpellParser
android.widget.Spinner
+android.widget.Spinner$SpinnerPopup
android.widget.SpinnerAdapter
+android.widget.Switch
+android.widget.Switch$1
android.widget.TextView
android.widget.TextView$3
android.widget.TextView$BufferType
@@ -2460,6 +2483,7 @@
android.widget.TextView$Drawables
android.widget.TextView$OnEditorActionListener
android.widget.TextView$SavedState
+android.widget.TextView$SavedState$1
android.widget.ThemedSpinnerAdapter
android.widget.Toast
android.widget.Toast$TN
@@ -2470,7 +2494,6 @@
android.widget.Toolbar$2
android.widget.Toolbar$ExpandedActionViewMenuPresenter
android.widget.Toolbar$LayoutParams
-android.widget.ViewAnimator
android.widget.WrapperListAdapter
com.android.dex.Annotation
com.android.dex.ClassData
@@ -2511,9 +2534,10 @@
com.android.internal.app.IAppOpsService
com.android.internal.app.IAppOpsService$Stub
com.android.internal.app.IAppOpsService$Stub$Proxy
+com.android.internal.app.IBatteryStats
+com.android.internal.app.IBatteryStats$Stub
com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
-com.android.internal.app.WindowDecorActionBar
com.android.internal.appwidget.IAppWidgetService
com.android.internal.appwidget.IAppWidgetService$Stub
com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
@@ -2521,6 +2545,8 @@
com.android.internal.content.ReferrerIntent
com.android.internal.content.ReferrerIntent$1
com.android.internal.inputmethod.InputMethodUtils
+com.android.internal.inputmethod.InputMethodUtils$1
+com.android.internal.inputmethod.LocaleUtils$LocaleExtractor
com.android.internal.logging.AndroidConfig
com.android.internal.logging.AndroidHandler
com.android.internal.logging.AndroidHandler$1
@@ -2575,6 +2601,9 @@
com.android.internal.util.FastXmlSerializer
com.android.internal.util.GrowingArrayUtils
com.android.internal.util.LineBreakBufferedWriter
+com.android.internal.util.MessageUtils
+com.android.internal.util.NotificationColorUtil
+com.android.internal.util.NotificationColorUtil$ColorUtilsFromCompat
com.android.internal.util.Preconditions
com.android.internal.util.VirtualRefBasePtr
com.android.internal.util.XmlUtils
@@ -2613,13 +2642,9 @@
com.android.internal.view.menu.MenuPresenter$Callback
com.android.internal.view.menu.MenuView
com.android.internal.view.menu.ShowableListMenu
-com.android.internal.widget.ActionBarOverlayLayout$ActionBarVisibilityCallback
-com.android.internal.widget.AlertDialogLayout
com.android.internal.widget.BackgroundFallback
-com.android.internal.widget.ButtonBarLayout
com.android.internal.widget.DecorContentParent
com.android.internal.widget.DecorToolbar
-com.android.internal.widget.DialogTitle
com.android.internal.widget.EditableInputConnection
com.android.internal.widget.ScrollBarUtils
com.android.internal.widget.ToolbarWidgetWrapper
@@ -2884,7 +2909,6 @@
dalvik.system.CloseGuard$DefaultReporter
dalvik.system.CloseGuard$Reporter
dalvik.system.DalvikLogHandler
-dalvik.system.DalvikLogging
dalvik.system.DexClassLoader
dalvik.system.DexFile
dalvik.system.DexFile$DFEnum
@@ -2911,6 +2935,7 @@
java.io.ByteArrayOutputStream
java.io.CharArrayWriter
java.io.Closeable
+java.io.Console
java.io.DataInput
java.io.DataInputStream
java.io.DataOutput
@@ -2922,15 +2947,14 @@
java.io.Externalizable
java.io.File
java.io.File$PathStatus
-java.io.File$TempDirectory
java.io.FileDescriptor
+java.io.FileFilter
java.io.FileInputStream
java.io.FileInputStream$UseManualSkipException
java.io.FileNotFoundException
java.io.FileOutputStream
java.io.FileReader
java.io.FileSystem
-java.io.FileWriter
java.io.FilenameFilter
java.io.FilterInputStream
java.io.FilterOutputStream
@@ -2941,7 +2965,6 @@
java.io.InputStreamReader
java.io.InterruptedIOException
java.io.InvalidObjectException
-java.io.NotSerializableException
java.io.ObjectInput
java.io.ObjectInputStream
java.io.ObjectInputStream$BlockDataInputStream
@@ -3013,6 +3036,7 @@
java.lang.EnumConstantNotPresentException
java.lang.Error
java.lang.Exception
+java.lang.ExceptionInInitializerError
java.lang.Float
java.lang.FloatingDecimal
java.lang.FloatingDecimal$1
@@ -3056,7 +3080,6 @@
java.lang.RuntimeException
java.lang.RuntimePermission
java.lang.SecurityException
-java.lang.SecurityManager
java.lang.Short
java.lang.Short$ShortCache
java.lang.Shutdown
@@ -3133,7 +3156,6 @@
java.math.BigInt
java.math.BigInteger
java.math.BitLevel
-java.math.Multiplication
java.math.NativeBN
java.math.RoundingMode
java.net.AbstractPlainDatagramSocketImpl
@@ -3260,22 +3282,18 @@
java.security.AlgorithmParameters
java.security.AlgorithmParametersSpi
java.security.BasicPermission
-java.security.BasicPermissionCollection
java.security.CryptoPrimitive
java.security.GeneralSecurityException
java.security.Guard
java.security.InvalidAlgorithmParameterException
java.security.InvalidKeyException
-java.security.InvalidParameterException
java.security.Key
java.security.KeyException
java.security.KeyFactory
java.security.KeyFactorySpi
java.security.KeyManagementException
-java.security.KeyPair
java.security.KeyStore
java.security.KeyStore$1
-java.security.KeyStore$LoadStoreParameter
java.security.KeyStoreException
java.security.KeyStoreSpi
java.security.MessageDigest
@@ -3285,6 +3303,7 @@
java.security.NoSuchProviderException
java.security.Permission
java.security.PermissionCollection
+java.security.Permissions
java.security.Principal
java.security.PrivateKey
java.security.PrivilegedAction
@@ -3332,7 +3351,6 @@
java.security.cert.PKIXRevocationChecker
java.security.cert.PolicyNode
java.security.cert.TrustAnchor
-java.security.cert.X509CRL
java.security.cert.X509CertSelector
java.security.cert.X509Certificate
java.security.cert.X509Extension
@@ -3342,7 +3360,6 @@
java.security.interfaces.ECPrivateKey
java.security.interfaces.ECPublicKey
java.security.interfaces.RSAKey
-java.security.interfaces.RSAPrivateCrtKey
java.security.interfaces.RSAPrivateKey
java.security.interfaces.RSAPublicKey
java.security.spec.AlgorithmParameterSpec
@@ -3351,19 +3368,14 @@
java.security.spec.ECFieldFp
java.security.spec.ECParameterSpec
java.security.spec.ECPoint
-java.security.spec.ECPrivateKeySpec
java.security.spec.ECPublicKeySpec
java.security.spec.EllipticCurve
java.security.spec.EncodedKeySpec
java.security.spec.InvalidKeySpecException
java.security.spec.InvalidParameterSpecException
java.security.spec.KeySpec
-java.security.spec.PKCS8EncodedKeySpec
-java.security.spec.RSAPrivateCrtKeySpec
-java.security.spec.RSAPrivateKeySpec
java.security.spec.RSAPublicKeySpec
java.security.spec.X509EncodedKeySpec
-java.sql.Timestamp
java.text.AttributedCharacterIterator$Attribute
java.text.CalendarBuilder
java.text.Collator
@@ -3401,7 +3413,9 @@
java.util.AbstractSequentialList
java.util.AbstractSet
java.util.ArrayDeque
+java.util.ArrayDeque$DeqIterator
java.util.ArrayList
+java.util.ArrayList$ArrayListSpliterator
java.util.ArrayList$Itr
java.util.ArrayList$ListItr
java.util.ArrayList$SubList
@@ -3414,6 +3428,7 @@
java.util.Collections
java.util.Collections$1
java.util.Collections$2
+java.util.Collections$3
java.util.Collections$AsLIFOQueue
java.util.Collections$CheckedCollection
java.util.Collections$CheckedList
@@ -3456,6 +3471,14 @@
java.util.Collections$UnmodifiableSortedSet
java.util.ComparableTimSort
java.util.Comparator
+java.util.Comparator$-java_util_Comparator_comparingDouble_java_util_function_ToDoubleFunction_keyExtractor_LambdaImpl0
+java.util.Comparator$-java_util_Comparator_comparingInt_java_util_function_ToIntFunction_keyExtractor_LambdaImpl0
+java.util.Comparator$-java_util_Comparator_comparingLong_java_util_function_ToLongFunction_keyExtractor_LambdaImpl0
+java.util.Comparator$-java_util_Comparator_comparing_java_util_function_Function_keyExtractor_LambdaImpl0
+java.util.Comparator$-java_util_Comparator_comparing_java_util_function_Function_keyExtractor_java_util_Comparator_keyComparator_LambdaImpl0
+java.util.Comparator$-java_util_Comparator_thenComparing_java_util_Comparator_other_LambdaImpl0
+java.util.Comparators$NaturalOrderComparator
+java.util.Comparators$NullComparator
java.util.ConcurrentModificationException
java.util.Currency
java.util.Date
@@ -3464,7 +3487,6 @@
java.util.DualPivotQuicksort
java.util.EnumMap
java.util.EnumMap$1
-java.util.EnumMap$EnumMapIterator
java.util.EnumSet
java.util.Enumeration
java.util.EventListener
@@ -3497,8 +3519,6 @@
java.util.Hashtable$KeySet
java.util.Hashtable$ValueCollection
java.util.IdentityHashMap
-java.util.IdentityHashMap$EntryIterator
-java.util.IdentityHashMap$EntrySet
java.util.IdentityHashMap$IdentityHashMapIterator
java.util.IdentityHashMap$KeySet
java.util.IllegalFormatException
@@ -3538,7 +3558,6 @@
java.util.RandomAccess
java.util.RandomAccessSubList
java.util.RegularEnumSet
-java.util.RegularEnumSet$EnumSetIterator
java.util.ResourceBundle
java.util.ResourceBundle$1
java.util.ResourceBundle$BundleReference
@@ -3550,7 +3569,6 @@
java.util.ResourceBundle$LoaderReference
java.util.ResourceBundle$RBClassLoader
java.util.ResourceBundle$RBClassLoader$1
-java.util.Scanner
java.util.ServiceLoader
java.util.ServiceLoader$1
java.util.ServiceLoader$LazyIterator
@@ -3558,6 +3576,17 @@
java.util.SimpleTimeZone
java.util.SortedMap
java.util.SortedSet
+java.util.Spliterator
+java.util.Spliterator$OfDouble
+java.util.Spliterator$OfInt
+java.util.Spliterator$OfLong
+java.util.Spliterator$OfPrimitive
+java.util.Spliterators
+java.util.Spliterators$EmptySpliterator
+java.util.Spliterators$EmptySpliterator$OfDouble
+java.util.Spliterators$EmptySpliterator$OfInt
+java.util.Spliterators$EmptySpliterator$OfLong
+java.util.Spliterators$EmptySpliterator$OfRef
java.util.Stack
java.util.StringTokenizer
java.util.SubList
@@ -3569,12 +3598,10 @@
java.util.TimerTask
java.util.TimerThread
java.util.TreeMap
-java.util.TreeMap$AscendingSubMap
java.util.TreeMap$EntryIterator
java.util.TreeMap$EntrySet
java.util.TreeMap$KeyIterator
java.util.TreeMap$KeySet
-java.util.TreeMap$NavigableSubMap
java.util.TreeMap$PrivateEntryIterator
java.util.TreeMap$TreeMapEntry
java.util.TreeMap$ValueIterator
@@ -3595,14 +3622,12 @@
java.util.WeakHashMap$Values
java.util.XMLUtils
java.util.concurrent.AbstractExecutorService
-java.util.concurrent.ArrayBlockingQueue
java.util.concurrent.BlockingQueue
java.util.concurrent.Callable
java.util.concurrent.CancellationException
java.util.concurrent.ConcurrentHashMap
java.util.concurrent.ConcurrentHashMap$BaseIterator
java.util.concurrent.ConcurrentHashMap$CollectionView
-java.util.concurrent.ConcurrentHashMap$CounterCell
java.util.concurrent.ConcurrentHashMap$ForwardingNode
java.util.concurrent.ConcurrentHashMap$KeyIterator
java.util.concurrent.ConcurrentHashMap$KeySetView
@@ -3611,8 +3636,6 @@
java.util.concurrent.ConcurrentHashMap$Traverser
java.util.concurrent.ConcurrentHashMap$TreeBin
java.util.concurrent.ConcurrentHashMap$TreeNode
-java.util.concurrent.ConcurrentHashMap$ValueIterator
-java.util.concurrent.ConcurrentHashMap$ValuesView
java.util.concurrent.ConcurrentLinkedQueue
java.util.concurrent.ConcurrentLinkedQueue$Node
java.util.concurrent.ConcurrentMap
@@ -3689,6 +3712,16 @@
java.util.concurrent.locks.ReentrantReadWriteLock$Sync
java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter
java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock
+java.util.function.BiConsumer
+java.util.function.BiFunction
+java.util.function.Consumer
+java.util.function.Function
+java.util.function.Predicate
+java.util.function.Supplier
+java.util.function.ToDoubleFunction
+java.util.function.ToIntFunction
+java.util.function.ToLongFunction
+java.util.function.UnaryOperator
java.util.jar.JarEntry
java.util.jar.JarFile
java.util.jar.JarFile$1
@@ -3709,15 +3742,19 @@
java.util.logging.LogManager$LoggerWeakRef
java.util.logging.LogManager$RootLogger
java.util.logging.LogManager$SystemLoggerContext
-java.util.logging.LogRecord
java.util.logging.Logger
java.util.logging.LoggingPermission
java.util.logging.LoggingProxyImpl
+java.util.prefs.AbstractPreferences
+java.util.prefs.Preferences
java.util.regex.MatchResult
java.util.regex.Matcher
java.util.regex.Pattern
java.util.regex.PatternSyntaxException
java.util.spi.LocaleServiceProvider
+java.util.stream.BaseStream
+java.util.stream.Stream
+java.util.stream.StreamSupport
java.util.zip.Adler32
java.util.zip.CRC32
java.util.zip.CheckedInputStream
@@ -3748,7 +3785,6 @@
javax.crypto.CipherSpi
javax.crypto.IllegalBlockSizeException
javax.crypto.JceSecurity
-javax.crypto.Mac
javax.crypto.NoSuchPaddingException
javax.crypto.NullCipher
javax.crypto.SecretKey
@@ -3757,10 +3793,6 @@
javax.crypto.spec.SecretKeySpec
javax.microedition.khronos.egl.EGL
javax.microedition.khronos.egl.EGL10
-javax.microedition.khronos.egl.EGLConfig
-javax.microedition.khronos.egl.EGLContext
-javax.microedition.khronos.egl.EGLDisplay
-javax.microedition.khronos.egl.EGLSurface
javax.microedition.khronos.opengles.GL
javax.microedition.khronos.opengles.GL10
javax.microedition.khronos.opengles.GL10Ext
@@ -3771,7 +3803,6 @@
javax.net.ServerSocketFactory
javax.net.SocketFactory
javax.net.ssl.ExtendedSSLSession
-javax.net.ssl.HandshakeCompletedEvent
javax.net.ssl.HandshakeCompletedListener
javax.net.ssl.HostnameVerifier
javax.net.ssl.HttpsURLConnection
@@ -3779,23 +3810,20 @@
javax.net.ssl.KeyManagerFactory
javax.net.ssl.KeyManagerFactory$1
javax.net.ssl.KeyManagerFactorySpi
+javax.net.ssl.SNIHostName
+javax.net.ssl.SNIServerName
javax.net.ssl.SSLContext
javax.net.ssl.SSLContextSpi
javax.net.ssl.SSLEngine
javax.net.ssl.SSLException
-javax.net.ssl.SSLHandshakeException
javax.net.ssl.SSLParameters
javax.net.ssl.SSLPeerUnverifiedException
javax.net.ssl.SSLProtocolException
-javax.net.ssl.SSLServerSocket
javax.net.ssl.SSLServerSocketFactory
javax.net.ssl.SSLSession
-javax.net.ssl.SSLSessionBindingEvent
-javax.net.ssl.SSLSessionBindingListener
javax.net.ssl.SSLSessionContext
javax.net.ssl.SSLSocket
javax.net.ssl.SSLSocketFactory
-javax.net.ssl.SSLSocketFactory$1
javax.net.ssl.TrustManager
javax.net.ssl.TrustManagerFactory
javax.net.ssl.TrustManagerFactory$1
@@ -3841,7 +3869,6 @@
libcore.io.NioBufferIterator
libcore.io.Os
libcore.io.Posix
-libcore.math.MathUtils
libcore.net.NetworkSecurityPolicy
libcore.net.NetworkSecurityPolicy$DefaultNetworkSecurityPolicy
libcore.net.UriCodec
@@ -3857,7 +3884,6 @@
libcore.reflect.ListOfTypes
libcore.reflect.ListOfVariables
libcore.reflect.ParameterizedTypeImpl
-libcore.reflect.TypeVariableImpl
libcore.reflect.Types
libcore.util.BasicLruCache
libcore.util.CharsetUtils
@@ -3866,7 +3892,6 @@
libcore.util.NativeAllocationRegistry
libcore.util.NativeAllocationRegistry$CleanerRunner
libcore.util.NativeAllocationRegistry$CleanerThunk
-libcore.util.Objects
libcore.util.ZoneInfo
libcore.util.ZoneInfo$CheckedArithmeticException
libcore.util.ZoneInfo$WallTime
@@ -3892,11 +3917,8 @@
org.apache.http.HttpResponse
org.apache.http.HttpVersion
org.apache.http.NameValuePair
-org.apache.http.ProtocolException
org.apache.http.ProtocolVersion
-org.apache.http.ReasonPhraseCatalog
org.apache.http.StatusLine
-org.apache.http.client.ClientProtocolException
org.apache.http.client.HttpClient
org.apache.http.client.ResponseHandler
org.apache.http.client.methods.AbortableHttpRequest
@@ -3905,26 +3927,15 @@
org.apache.http.client.methods.HttpPost
org.apache.http.client.methods.HttpRequestBase
org.apache.http.client.methods.HttpUriRequest
-org.apache.http.client.utils.URLEncodedUtils
org.apache.http.conn.ClientConnectionManager
org.apache.http.conn.ConnectTimeoutException
-org.apache.http.conn.params.ConnManagerPNames
-org.apache.http.conn.params.ConnManagerParams
-org.apache.http.conn.params.ConnManagerParams$1
-org.apache.http.conn.params.ConnPerRoute
-org.apache.http.conn.scheme.LayeredSocketFactory
-org.apache.http.conn.scheme.SocketFactory
org.apache.http.entity.AbstractHttpEntity
-org.apache.http.entity.BasicHttpEntity
org.apache.http.entity.ByteArrayEntity
-org.apache.http.impl.client.EntityEnclosingRequestWrapper
-org.apache.http.impl.client.RequestWrapper
org.apache.http.impl.cookie.DateParseException
org.apache.http.impl.cookie.DateUtils
org.apache.http.message.AbstractHttpMessage
org.apache.http.message.BasicHeader
org.apache.http.message.BasicHttpResponse
-org.apache.http.message.BasicNameValuePair
org.apache.http.message.BasicStatusLine
org.apache.http.message.HeaderGroup
org.apache.http.params.AbstractHttpParams
@@ -3933,6 +3944,18 @@
org.apache.http.params.HttpConnectionParams
org.apache.http.params.HttpParams
org.apache.http.protocol.HttpContext
+org.ccil.cowan.tagsoup.AttributesImpl
+org.ccil.cowan.tagsoup.AutoDetector
+org.ccil.cowan.tagsoup.Element
+org.ccil.cowan.tagsoup.ElementType
+org.ccil.cowan.tagsoup.HTMLModels
+org.ccil.cowan.tagsoup.HTMLScanner
+org.ccil.cowan.tagsoup.HTMLSchema
+org.ccil.cowan.tagsoup.Parser
+org.ccil.cowan.tagsoup.Parser$1
+org.ccil.cowan.tagsoup.ScanHandler
+org.ccil.cowan.tagsoup.Scanner
+org.ccil.cowan.tagsoup.Schema
org.json.JSON
org.json.JSONArray
org.json.JSONException
@@ -3954,6 +3977,7 @@
org.xml.sax.SAXNotRecognizedException
org.xml.sax.SAXNotSupportedException
org.xml.sax.XMLReader
+org.xml.sax.ext.LexicalHandler
org.xml.sax.helpers.DefaultHandler
org.xmlpull.v1.XmlPullParser
org.xmlpull.v1.XmlPullParserException
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index ea3cffe..afea7f3 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2138,6 +2138,20 @@
// Settings > Apps > Gear > Special Access > Premium SMS access
PREMIUM_SMS_ACCESS = 388;
+ // Logged when the user resizes the docked stack. Arguments:
+ // 0: Split 50:50
+ // 1: Docked smaller
+ // 2: Docked larger
+ ACTION_WINDOW_DOCK_RESIZE = 389;
+
+ // User exits split-screen by dragging the divider to the side of the screen. Arguments
+ // 0: Docked gets maximized
+ // 1: Fullscreen gets maximized
+ ACTION_WINDOW_UNDOCK_MAX = 390;
+
+ // User tried to dock an unresizable app.
+ ACTION_WINDOW_DOCK_UNRESIZABLE = 391;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 9ec6e8d..04ea8e5 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -58,6 +58,7 @@
private static final int MAX_NUMBER_IO_INPUT_ALLOC = 16;
Type mType;
+ boolean mOwningType = false;
Bitmap mBitmap;
int mUsage;
Allocation mAdaptedAllocation;
@@ -383,13 +384,16 @@
guard.open("destroy");
}
- Allocation(long id, RenderScript rs, Type t, int usage, MipmapControl mips) {
+ Allocation(long id, RenderScript rs, Type t, boolean owningType, int usage, MipmapControl mips) {
this(id, rs, t, usage);
+ mOwningType = owningType;
mMipmapControl = mips;
}
protected void finalize() throws Throwable {
RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
+ // Set mType null to avoid double-destroying it in case its finalizer races ahead
+ mType = null;
super.finalize();
}
@@ -1578,6 +1582,9 @@
mRS.finish(); // Necessary because resize is fifoed and update is async.
long typeID = mRS.nAllocationGetType(getID(mRS));
+ // Sets zero the mID so that the finalizer of the old mType value won't
+ // destroy the native object that is being reused.
+ mType.setID(0);
mType = new Type(typeID, mRS);
mType.updateFromNative();
updateCacheInfo(mType);
@@ -1921,7 +1928,7 @@
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
}
- return new Allocation(id, rs, type, usage, mips);
+ return new Allocation(id, rs, type, false, usage, mips);
} finally {
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -1979,7 +1986,7 @@
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
}
- return new Allocation(id, rs, t, usage, MipmapControl.MIPMAP_NONE);
+ return new Allocation(id, rs, t, true, usage, MipmapControl.MIPMAP_NONE);
} finally {
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -2068,7 +2075,7 @@
}
// keep a reference to the Bitmap around to prevent GC
- Allocation alloc = new Allocation(id, rs, t, usage, mips);
+ Allocation alloc = new Allocation(id, rs, t, true, usage, mips);
alloc.setBitmap(b);
return alloc;
}
@@ -2078,7 +2085,7 @@
if (id == 0) {
throw new RSRuntimeException("Load failed.");
}
- return new Allocation(id, rs, t, usage, mips);
+ return new Allocation(id, rs, t, true, usage, mips);
} finally {
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -2150,7 +2157,7 @@
}
for (int i=1; i<numAlloc; i++) {
- mAllocationArray[i] = createFromAllcation(rs, mAllocationArray[0]);
+ mAllocationArray[i] = createFromAllocation(rs, mAllocationArray[0]);
}
return mAllocationArray;
} finally {
@@ -2169,7 +2176,7 @@
* @param alloc RenderScript Allocation describing data layout.
* @return Allocation sharing the same data structure.
*/
- static Allocation createFromAllcation(RenderScript rs, Allocation alloc) {
+ static Allocation createFromAllocation(RenderScript rs, Allocation alloc) {
try {
Trace.traceBegin(RenderScript.TRACE_TAG, "createFromAllcation");
rs.validate();
@@ -2184,7 +2191,7 @@
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
}
- Allocation outAlloc = new Allocation(id, rs, type, usage, mips);
+ Allocation outAlloc = new Allocation(id, rs, type, false, usage, mips);
if ((usage & USAGE_IO_INPUT) != 0) {
outAlloc.shareBufferQueue(alloc);
}
@@ -2360,7 +2367,7 @@
if(id == 0) {
throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
}
- return new Allocation(id, rs, t, usage, mips);
+ return new Allocation(id, rs, t, true, usage, mips);
}
/**
@@ -2605,6 +2612,13 @@
if((mUsage & USAGE_IO_OUTPUT) != 0) {
setSurface(null);
}
+
+ if (mType != null && mOwningType) {
+ mType.destroy();
+ mType = null;
+ }
+
super.destroy();
}
+
}
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index 219f16b..35ae8b4 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -187,6 +187,23 @@
guard.open("destroy");
}
+ /**
+ * Destroys this Closure and the Allocation for its return value
+ */
+ public void destroy() {
+ super.destroy();
+ if (mReturnValue != null) {
+ mReturnValue.destroy();
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ // Set null mReturnValue to avoid double-destroying it, in case its
+ // finalizer races ahead.
+ mReturnValue = null;
+ super.finalize();
+ }
+
private void retrieveValueAndDependenceInfo(RenderScript rs,
int index, Script.FieldID fid, Object obj,
long[] values, int[] sizes,
@@ -1015,6 +1032,8 @@
throw new RSIllegalArgumentException("invalid script group name");
}
ScriptGroup ret = new ScriptGroup(mRS, name, mClosures, mInputs, outputs);
+ mClosures = new ArrayList<Closure>();
+ mInputs = new ArrayList<Input>();
return ret;
}
@@ -1042,4 +1061,20 @@
}
+ /**
+ * Destroy this ScriptGroup and all Closures in it
+ */
+ public void destroy() {
+ super.destroy();
+ for(Closure c : mClosures) {
+ c.destroy();
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ // Clear out the list mClosures to avoid double-destroying the closures,
+ // in case their finalizers race ahead.
+ mClosures.clear();
+ super.finalize();
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 613f890..4d7f82d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -70,12 +70,22 @@
static final int FLAG_FEATURE_AUTOCLICK = 0x00000008;
/**
- * Flag for enabling motion event injectsion
+ * Flag for enabling motion event injection.
*
* @see #setUserAndEnabledFeatures(int, int)
*/
static final int FLAG_FEATURE_INJECT_MOTION_EVENTS = 0x00000010;
+ /**
+ * Flag for enabling the feature to control the screen magnifier. If
+ * {@link #FLAG_FEATURE_SCREEN_MAGNIFIER} is set this flag is ignored
+ * as the screen magnifier feature performs a super set of the work
+ * performed by this feature.
+ *
+ * @see #setUserAndEnabledFeatures(int, int)
+ */
+ static final int FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER = 0x00000020;
+
private final Runnable mProcessBatchedEventsRunnable = new Runnable() {
@Override
public void run() {
@@ -373,8 +383,12 @@
addFirstEventHandler(mTouchExplorer);
}
- if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
- mMagnificationGestureHandler = new MagnificationGestureHandler(mContext, mAms);
+ if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
+ || (mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
+ final boolean detectControlGestures = (mEnabledFeatures
+ & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0;
+ mMagnificationGestureHandler = new MagnificationGestureHandler(
+ mContext, mAms, detectControlGestures);
addFirstEventHandler(mMagnificationGestureHandler);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ca17c43..d900b37 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1311,6 +1311,9 @@
if (userState.mIsDisplayMagnificationEnabled) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
}
+ if (userHasMagnificationServicesLocked(userState)) {
+ flags |= AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER;
+ }
// Touch exploration without accessibility makes no sense.
if (userState.isHandlingAccessibilityEvents()
&& userState.mIsTouchExplorationEnabled) {
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index fb1ef37..b2196bf 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -156,10 +156,10 @@
final float offsetY = sentSpec.offsetY;
// Compute the new center and update spec as needed.
- final float centerX = (mMagnifiedBounds.width() / 2.0f - offsetX) / scale
- + mMagnifiedBounds.left;
- final float centerY = (mMagnifiedBounds.height() / 2.0f - offsetY) / scale
- + mMagnifiedBounds.top;
+ final float centerX = (mMagnifiedBounds.width() / 2.0f
+ + mMagnifiedBounds.left - offsetX) / scale;
+ final float centerY = (mMagnifiedBounds.height() / 2.0f
+ + mMagnifiedBounds.top - offsetY) / scale;
if (updateSpec) {
setScaleAndCenter(scale, centerX, centerY, false);
} else {
@@ -256,7 +256,7 @@
public float getCenterX() {
synchronized (mLock) {
return (mMagnifiedBounds.width() / 2.0f
- - getOffsetX()) / getScale() + mMagnifiedBounds.left;
+ + mMagnifiedBounds.left - getOffsetX()) / getScale();
}
}
@@ -279,7 +279,7 @@
public float getCenterY() {
synchronized (mLock) {
return (mMagnifiedBounds.height() / 2.0f
- - getOffsetY()) / getScale() + mMagnifiedBounds.top;
+ + mMagnifiedBounds.top - getOffsetY()) / getScale();
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 51c8ab5..818ac81 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -80,7 +80,6 @@
private static final boolean DEBUG_STATE_TRANSITIONS = false;
private static final boolean DEBUG_DETECTING = false;
private static final boolean DEBUG_PANNING = false;
- private static final boolean DEBUG_SCALING = false;
private static final int STATE_DELEGATING = 1;
private static final int STATE_DETECTING = 2;
@@ -95,6 +94,9 @@
private final MagnifiedContentInteractionStateHandler mMagnifiedContentInteractionStateHandler;
private final StateViewportDraggingHandler mStateViewportDraggingHandler;
+
+ private final boolean mDetectControlGestures;
+
private EventStreamTransformation mNext;
private int mCurrentState;
@@ -107,12 +109,14 @@
private long mDelegatingStateDownTime;
- public MagnificationGestureHandler(Context context, AccessibilityManagerService ams) {
+ public MagnificationGestureHandler(Context context, AccessibilityManagerService ams,
+ boolean detectControlGestures) {
mMagnificationController = ams.getMagnificationController();
mDetectingStateHandler = new DetectingStateHandler(context);
mStateViewportDraggingHandler = new StateViewportDraggingHandler();
mMagnifiedContentInteractionStateHandler =
new MagnifiedContentInteractionStateHandler(context);
+ mDetectControlGestures = detectControlGestures;
transitionToState(STATE_DETECTING);
}
@@ -125,6 +129,12 @@
}
return;
}
+ if (!mDetectControlGestures) {
+ if (mNext != null) {
+ dispatchTransformedEvent(event, rawEvent, policyFlags);
+ }
+ return;
+ }
mMagnifiedContentInteractionStateHandler.onMotionEvent(event, rawEvent, policyFlags);
switch (mCurrentState) {
case STATE_DELEGATING: {
@@ -140,7 +150,7 @@
}
break;
case STATE_MAGNIFIED_INTERACTION: {
- // mMagnifiedContentInteractonStateHandler handles events only
+ // mMagnifiedContentInteractionStateHandler handles events only
// if this is the current state since it uses ScaleGestureDetecotr
// and a GestureDetector which need well formed event stream.
}
@@ -208,31 +218,6 @@
break;
}
if (mNext != null) {
- // If the event is within the magnified portion of the screen we have
- // to change its location to be where the user thinks he is poking the
- // UI which may have been magnified and panned.
- final float eventX = event.getX();
- final float eventY = event.getY();
- if (mMagnificationController.isMagnifying()
- && mMagnificationController.magnifiedRegionContains(eventX, eventY)) {
- final float scale = mMagnificationController.getScale();
- final float scaledOffsetX = mMagnificationController.getOffsetX();
- final float scaledOffsetY = mMagnificationController.getOffsetY();
- final int pointerCount = event.getPointerCount();
- PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
- PointerProperties[] properties = getTempPointerPropertiesWithMinSize(
- pointerCount);
- for (int i = 0; i < pointerCount; i++) {
- event.getPointerCoords(i, coords[i]);
- coords[i].x = (coords[i].x - scaledOffsetX) / scale;
- coords[i].y = (coords[i].y - scaledOffsetY) / scale;
- event.getPointerProperties(i, properties[i]);
- }
- event = MotionEvent.obtain(event.getDownTime(),
- event.getEventTime(), event.getAction(), pointerCount, properties,
- coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
- event.getFlags());
- }
// We cache some events to see if the user wants to trigger magnification.
// If no magnification is triggered we inject these events with adjusted
// time and down time to prevent subsequent transformations being confused
@@ -240,10 +225,40 @@
// injected we need to also update the down time of all subsequent non cached
// events. All delegated events cached and non-cached are delivered here.
event.setDownTime(mDelegatingStateDownTime);
- mNext.onMotionEvent(event, rawEvent, policyFlags);
+ dispatchTransformedEvent(event, rawEvent, policyFlags);
}
}
+ private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent,
+ int policyFlags) {
+ // If the event is within the magnified portion of the screen we have
+ // to change its location to be where the user thinks he is poking the
+ // UI which may have been magnified and panned.
+ final float eventX = event.getX();
+ final float eventY = event.getY();
+ if (mMagnificationController.isMagnifying()
+ && mMagnificationController.magnifiedRegionContains(eventX, eventY)) {
+ final float scale = mMagnificationController.getScale();
+ final float scaledOffsetX = mMagnificationController.getOffsetX();
+ final float scaledOffsetY = mMagnificationController.getOffsetY();
+ final int pointerCount = event.getPointerCount();
+ PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
+ PointerProperties[] properties = getTempPointerPropertiesWithMinSize(
+ pointerCount);
+ for (int i = 0; i < pointerCount; i++) {
+ event.getPointerCoords(i, coords[i]);
+ coords[i].x = (coords[i].x - scaledOffsetX) / scale;
+ coords[i].y = (coords[i].y - scaledOffsetY) / scale;
+ event.getPointerProperties(i, properties[i]);
+ }
+ event = MotionEvent.obtain(event.getDownTime(),
+ event.getEventTime(), event.getAction(), pointerCount, properties,
+ coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
+ event.getFlags());
+ }
+ mNext.onMotionEvent(event, rawEvent, policyFlags);
+ }
+
private PointerCoords[] getTempPointerCoordsWithMinSize(int size) {
final int oldSize = (mTempPointerCoords != null) ? mTempPointerCoords.length : 0;
if (oldSize < size) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 6ca3af8..0428ecf 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -613,23 +613,22 @@
| FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
}
}
+ for (int j = 0; j < widgetCount; j++) {
+ Widget widget = provider.widgets.get(j);
+ if (targetWidget != null && targetWidget != widget) continue;
+ PendingIntent intent = null;
+ if (onClickIntent != null) {
+ intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
+ onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+ RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
+ if (widget.replaceWithMaskedViewsLocked(views)) {
+ scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
+ }
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
-
- for (int j = 0; j < widgetCount; j++) {
- Widget widget = provider.widgets.get(j);
- if (targetWidget != null && targetWidget != widget) continue;
- PendingIntent intent = null;
- if (onClickIntent != null) {
- intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
- onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- }
- RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
- if (widget.replaceWithMaskedViewsLocked(views)) {
- scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
- }
- }
}
private void unmaskWidgetsViewsLocked(Provider provider) {
@@ -1062,8 +1061,6 @@
widget.provider = provider;
widget.options = (options != null) ? cloneIfLocalBinder(options) : new Bundle();
- onWidgetProviderAddedOrChangedLocked(widget);
-
// We need to provide a default value for the widget category if it is not specified
if (!widget.options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) {
widget.options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
@@ -1072,6 +1069,8 @@
provider.widgets.add(widget);
+ onWidgetProviderAddedOrChangedLocked(widget);
+
final int widgetCount = provider.widgets.size();
if (widgetCount == 1) {
// Tell the provider that it's ready.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 428e192..e5fe03a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2025,11 +2025,15 @@
default:
return false;
case NetworkMonitor.EVENT_NETWORK_TESTED: {
- NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
- if (isLiveNetworkAgent(nai, msg.what)) {
+ final NetworkAgentInfo nai;
+ synchronized (mNetworkForNetId) {
+ nai = mNetworkForNetId.get(msg.arg2);
+ }
+ if (nai != null) {
final boolean valid =
(msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
- if (DBG) log(nai.name() + " validation " + (valid ? " passed" : "failed"));
+ if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
+ (msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
if (valid != nai.lastValidated) {
final int oldScore = nai.getCurrentScore();
nai.lastValidated = valid;
@@ -2040,10 +2044,12 @@
}
updateInetCondition(nai);
// Let the NetworkAgent know the state of its network
+ Bundle redirectUrlBundle = new Bundle();
+ redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, (String)msg.obj);
nai.asyncChannel.sendMessage(
- android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS,
+ NetworkAgent.CMD_REPORT_NETWORK_STATUS,
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
- 0, null);
+ 0, redirectUrlBundle);
}
break;
}
@@ -2200,6 +2206,10 @@
}
mLegacyTypeTracker.remove(nai, wasDefault);
rematchAllNetworksAndRequests(null, 0);
+ if (wasDefault && getDefaultNetwork() == null) {
+ // Log that we lost the default network and there is no replacement.
+ logConnectivityServiceChangeEvent(null, nai);
+ }
if (nai.created) {
// Tell netd to clean up the configuration for this network
// (routing rules, DNS, etc).
@@ -4421,9 +4431,8 @@
teardownUnneededNetwork(oldNetwork);
}
- private void makeDefault(NetworkAgentInfo newNetwork) {
+ private void makeDefault(NetworkAgentInfo newNetwork, NetworkAgentInfo prevNetwork) {
if (DBG) log("Switching to new default network: " + newNetwork);
- ConnectivityServiceChangeEvent.logEvent(newNetwork.network.netId);
setupDataActivityTracking(newNetwork);
try {
mNetd.setDefaultNetId(newNetwork.network.netId);
@@ -4434,6 +4443,8 @@
handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
updateTcpBufferSizes(newNetwork);
setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
+
+ logConnectivityServiceChangeEvent(newNetwork, prevNetwork);
}
// Handles a network appearing or improving its score.
@@ -4584,7 +4595,7 @@
}
if (isNewDefault) {
// Notify system services that this network is up.
- makeDefault(newNetwork);
+ makeDefault(newNetwork, oldDefaultNetwork);
synchronized (ConnectivityService.this) {
// have a new default network, release the transition wakelock in
// a second if it's held. The second pause is to allow apps
@@ -5054,4 +5065,22 @@
NetworkAgentInfo nai, NetworkRequest defaultRequest) {
return new NetworkMonitor(context, handler, nai, defaultRequest);
}
+
+ private static void logConnectivityServiceChangeEvent(
+ NetworkAgentInfo next, NetworkAgentInfo prev) {
+ final int newNetId = (next == null) ? NETID_UNSET : next.network.netId;
+ final int[] newTransportTypes = (next == null)
+ ? new int[0]
+ : next.networkCapabilities.getTransportTypes();
+
+ final int oldNetId = (prev == null) ? NETID_UNSET : prev.network.netId;
+ final boolean hadIPv4 = (prev != null) &&
+ prev.linkProperties.hasIPv4Address() &&
+ prev.linkProperties.hasIPv4DefaultRoute();
+ final boolean hadIPv6 = (prev != null) &&
+ prev.linkProperties.hasGlobalIPv6Address() &&
+ prev.linkProperties.hasIPv6DefaultRoute();
+ ConnectivityServiceChangeEvent.logEvent(newNetId, newTransportTypes,
+ oldNetId, hadIPv4, hadIPv6);
+ }
}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 4ac75ca..f2b4e52 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -229,7 +229,6 @@
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
filter.addAction(Intent.ACTION_USER_REMOVED);
- filter.addAction(Intent.ACTION_USER_PRESENT);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
@@ -369,8 +368,6 @@
} else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mStorage.prefetchUser(userHandle);
- } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
- mStrongAuth.reportUnlock(getSendingUserId());
} else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
if (userHandle > 0) {
@@ -1347,6 +1344,12 @@
mStrongAuth.requireStrongAuth(strongAuthReason, userId);
}
+ @Override
+ public void userPresent(int userId) {
+ checkWritePermission(userId);
+ mStrongAuth.reportUnlock(userId);
+ }
+
private static final String[] VALID_SETTINGS = new String[] {
LockPatternUtils.LOCKOUT_PERMANENT_KEY,
LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index 7db9be2..6009984 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -243,7 +243,7 @@
log("Problem parsing message " + e);
} finally {
if (releaseWl) {
- mWakeLock.acquire();
+ mWakeLock.release();
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index bf4df94..fffd850 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -174,6 +174,16 @@
public static final int StrictCleartext = 617;
}
+ /**
+ * String indicating a softap command.
+ */
+ static final String SOFT_AP_COMMAND = "softap";
+
+ /**
+ * String passed back to netd connector indicating softap command success.
+ */
+ static final String SOFT_AP_COMMAND_SUCCESS = "Ok";
+
static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
/**
@@ -1426,20 +1436,48 @@
}
}
+ /**
+ * Private method used to call execute for a command given the provided arguments.
+ *
+ * This function checks the returned NativeDaemonEvent for the provided expected response code
+ * and message. If either of these is not correct, an error is logged.
+ *
+ * @param String command The command to execute.
+ * @param Object[] args If needed, arguments for the command to execute.
+ * @param int expectedResponseCode The code expected to be returned in the corresponding event.
+ * @param String expectedResponseMessage The message expected in the returned event.
+ * @param String logMsg The message to log as an error (TAG will be applied).
+ */
+ private void executeOrLogWithMessage(String command, Object[] args,
+ int expectedResponseCode, String expectedResponseMessage, String logMsg)
+ throws NativeDaemonConnectorException {
+ NativeDaemonEvent event = mConnector.execute(command, args);
+ if (event.getCode() != expectedResponseCode
+ || !event.getMessage().equals(expectedResponseMessage)) {
+ Log.e(TAG, logMsg + ": event = " + event);
+ }
+ }
+
@Override
- public void startAccessPoint(
- WifiConfiguration wifiConfig, String wlanIface) {
+ public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Object[] args;
+ String logMsg = "startAccessPoint Error setting up softap";
try {
if (wifiConfig == null) {
- mConnector.execute("softap", "set", wlanIface);
+ args = new Object[] {"set", wlanIface};
} else {
- mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
- "broadcast", Integer.toString(wifiConfig.apChannel),
- getSecurityType(wifiConfig),
- new SensitiveArg(wifiConfig.preSharedKey));
+ args = new Object[] {"set", wlanIface, wifiConfig.SSID,
+ "broadcast", Integer.toString(wifiConfig.apChannel),
+ getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
}
- mConnector.execute("softap", "startap");
+ executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+ SOFT_AP_COMMAND_SUCCESS, logMsg);
+
+ logMsg = "startAccessPoint Error starting softap";
+ args = new Object[] {"startap"};
+ executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+ SOFT_AP_COMMAND_SUCCESS, logMsg);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
@@ -1460,8 +1498,12 @@
@Override
public void wifiFirmwareReload(String wlanIface, String mode) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Object[] args = {"fwreload", wlanIface, mode};
+ String logMsg = "wifiFirmwareReload Error reloading "
+ + wlanIface + " fw in " + mode + " mode";
try {
- mConnector.execute("softap", "fwreload", wlanIface, mode);
+ executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+ SOFT_AP_COMMAND_SUCCESS, logMsg);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
@@ -1470,8 +1512,12 @@
@Override
public void stopAccessPoint(String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Object[] args = {"stopap"};
+ String logMsg = "stopAccessPoint Error stopping softap";
+
try {
- mConnector.execute("softap", "stopap");
+ executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+ SOFT_AP_COMMAND_SUCCESS, logMsg);
wifiFirmwareReload(wlanIface, "STA");
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
@@ -1481,14 +1527,21 @@
@Override
public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Object[] args;
+ String logMsg = "startAccessPoint Error setting up softap";
try {
if (wifiConfig == null) {
- mConnector.execute("softap", "set", wlanIface);
+ args = new Object[] {"set", wlanIface};
} else {
- mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
- "broadcast", "6", getSecurityType(wifiConfig),
- new SensitiveArg(wifiConfig.preSharedKey));
+ // TODO: understand why this is set to "6" instead of
+ // Integer.toString(wifiConfig.apChannel) as in startAccessPoint
+ // TODO: should startAccessPoint call this instead of repeating code?
+ args = new Object[] {"set", wlanIface, wifiConfig.SSID,
+ "broadcast", "6",
+ getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
}
+ executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+ SOFT_AP_COMMAND_SUCCESS, logMsg);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 2924cef..5ba07cf 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -454,6 +454,12 @@
return;
}
+ if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE
+ && Settings.System.getInt(
+ mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) == 0) {
+ return;
+ }
+
int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
vib.mUsageHint, vib.mUid, vib.mOpPkg);
if (mode == AppOpsManager.MODE_ALLOWED) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 05e4245..4791818 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -91,6 +91,8 @@
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
@@ -127,9 +129,34 @@
public class AccountManagerService
extends IAccountManager.Stub
implements RegisteredServicesCacheListener<AuthenticatorDescription> {
-
private static final String TAG = "AccountManagerService";
+ public static class Lifecycle extends SystemService {
+ private AccountManagerService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mService = new AccountManagerService(getContext());
+ publishBinderService(Context.ACCOUNT_SERVICE, mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mService.systemReady();
+ }
+ }
+
+ @Override
+ public void onUnlockUser(int userHandle) {
+ mService.onUnlockUser(userHandle);
+ }
+ }
+
private static final String DATABASE_NAME = "accounts.db";
private static final int PRE_N_DATABASE_VERSION = 9;
private static final int CE_DATABASE_VERSION = 10;
@@ -340,15 +367,12 @@
IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_REMOVED);
- userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_USER_REMOVED.equals(action)) {
onUserRemoved(intent);
- } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
- onUserUnlocked(intent);
}
}
}, UserHandle.ALL, userFilter, null, null);
@@ -654,7 +678,10 @@
@VisibleForTesting
void onUserUnlocked(Intent intent) {
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
+ }
+
+ void onUnlockUser(int userId) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "onUserUnlocked " + userId);
}
diff --git a/services/core/java/com/android/server/accounts/CryptoHelper.java b/services/core/java/com/android/server/accounts/CryptoHelper.java
index 2b59b74..2ade673 100644
--- a/services/core/java/com/android/server/accounts/CryptoHelper.java
+++ b/services/core/java/com/android/server/accounts/CryptoHelper.java
@@ -10,15 +10,12 @@
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
/**
* A crypto helper for encrypting and decrypting bundle with in-memory symmetric
@@ -30,15 +27,15 @@
private static final String KEY_CIPHER = "cipher";
private static final String KEY_MAC = "mac";
private static final String KEY_ALGORITHM = "AES";
+ private static final String KEY_IV = "iv";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String MAC_ALGORITHM = "HMACSHA256";
private static final int IV_LENGTH = 16;
private static CryptoHelper sInstance;
// Keys used for encrypting and decrypting data returned in a Bundle.
- private final SecretKeySpec mCipherKeySpec;
- private final SecretKeySpec mMacKeySpec;
- private final IvParameterSpec mIv;
+ private final SecretKey mEncryptionKey;
+ private final SecretKey mMacKey;
/* default */ synchronized static CryptoHelper getInstance() throws NoSuchAlgorithmException {
if (sInstance == null) {
@@ -49,18 +46,10 @@
private CryptoHelper() throws NoSuchAlgorithmException {
KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
- SecretKey skey = kgen.generateKey();
- mCipherKeySpec = new SecretKeySpec(skey.getEncoded(), KEY_ALGORITHM);
-
+ mEncryptionKey = kgen.generateKey();
+ // Use a different key for mac-ing than encryption/decryption.
kgen = KeyGenerator.getInstance(MAC_ALGORITHM);
- skey = kgen.generateKey();
- mMacKeySpec = new SecretKeySpec(skey.getEncoded(), MAC_ALGORITHM);
-
- // Create random iv
- byte[] iv = new byte[IV_LENGTH];
- SecureRandom secureRandom = new SecureRandom();
- secureRandom.nextBytes(iv);
- mIv = new IvParameterSpec(iv);
+ mMacKey = kgen.generateKey();
}
@NonNull
@@ -68,16 +57,19 @@
Preconditions.checkNotNull(bundle, "Cannot encrypt null bundle.");
Parcel parcel = Parcel.obtain();
bundle.writeToParcel(parcel, 0);
- byte[] bytes = parcel.marshall();
+ byte[] clearBytes = parcel.marshall();
parcel.recycle();
+ Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+ cipher.init(Cipher.ENCRYPT_MODE, mEncryptionKey);
+ byte[] encryptedBytes = cipher.doFinal(clearBytes);
+ byte[] iv = cipher.getIV();
+ byte[] mac = createMac(encryptedBytes, iv);
+
Bundle encryptedBundle = new Bundle();
-
- byte[] cipher = encrypt(bytes);
- byte[] mac = createMac(cipher);
-
- encryptedBundle.putByteArray(KEY_CIPHER, cipher);
+ encryptedBundle.putByteArray(KEY_CIPHER, encryptedBytes);
encryptedBundle.putByteArray(KEY_MAC, mac);
+ encryptedBundle.putByteArray(KEY_IV, iv);
return encryptedBundle;
}
@@ -85,19 +77,18 @@
@Nullable
/* default */ Bundle decryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException {
Preconditions.checkNotNull(bundle, "Cannot decrypt null bundle.");
- byte[] cipherArray = bundle.getByteArray(KEY_CIPHER);
- byte[] macArray = bundle.getByteArray(KEY_MAC);
-
- if (!verifyMac(cipherArray, macArray)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Escrow mac mismatched!");
- }
+ byte[] iv = bundle.getByteArray(KEY_IV);
+ byte[] encryptedBytes = bundle.getByteArray(KEY_CIPHER);
+ byte[] mac = bundle.getByteArray(KEY_MAC);
+ if (!verifyMac(encryptedBytes, iv, mac)) {
+ Log.w(TAG, "Escrow mac mismatched!");
return null;
}
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
- cipher.init(Cipher.DECRYPT_MODE, mCipherKeySpec, mIv);
- byte[] decryptedBytes = cipher.doFinal(cipherArray);
+ cipher.init(Cipher.DECRYPT_MODE, mEncryptionKey, ivSpec);
+ byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
Parcel decryptedParcel = Parcel.obtain();
decryptedParcel.unmarshall(decryptedBytes, 0, decryptedBytes.length);
@@ -108,9 +99,8 @@
return decryptedBundle;
}
- private boolean verifyMac(@Nullable byte[] cipherArray, @Nullable byte[] macArray)
+ private boolean verifyMac(@Nullable byte[] cipherArray, @Nullable byte[] iv, @Nullable byte[] macArray)
throws GeneralSecurityException {
-
if (cipherArray == null || cipherArray.length == 0 || macArray == null
|| macArray.length == 0) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -118,23 +108,29 @@
}
return false;
}
- Mac mac = Mac.getInstance(MAC_ALGORITHM);
- mac.init(mMacKeySpec);
- mac.update(cipherArray);
- return Arrays.equals(macArray, mac.doFinal());
+ return constantTimeArrayEquals(macArray, createMac(cipherArray, iv));
}
@NonNull
- private byte[] encrypt(@NonNull byte[] data) throws GeneralSecurityException {
- Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
- cipher.init(Cipher.ENCRYPT_MODE, mCipherKeySpec, mIv);
- return cipher.doFinal(data);
+ private byte[] createMac(@NonNull byte[] cipher, @NonNull byte[] iv) throws GeneralSecurityException {
+ Mac mac = Mac.getInstance(MAC_ALGORITHM);
+ mac.init(mMacKey);
+ mac.update(cipher);
+ mac.update(iv);
+ return mac.doFinal();
}
- @NonNull
- private byte[] createMac(@NonNull byte[] cipher) throws GeneralSecurityException {
- Mac mac = Mac.getInstance(MAC_ALGORITHM);
- mac.init(mMacKeySpec);
- return mac.doFinal(cipher);
+ private static boolean constantTimeArrayEquals(byte[] a, byte[] b) {
+ if (a == null || b == null) {
+ return a == b;
+ }
+ if (a.length != b.length) {
+ return false;
+ }
+ boolean isEqual = true;
+ for (int i = 0; i < b.length; i++) {
+ isEqual &= (a[i] == b[i]);
+ }
+ return isEqual;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3ec51e3..04a63a1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8792,6 +8792,7 @@
rti.bounds = new Rect(tr.mBounds);
}
rti.isDockable = tr.canGoInDockedStack();
+ rti.resizeMode = tr.mResizeMode;
ActivityRecord base = null;
ActivityRecord top = null;
@@ -9424,7 +9425,8 @@
if (prev != null && prev.isRecentsActivity()) {
task.setTaskToReturnTo(ActivityRecord.RECENTS_ACTIVITY_TYPE);
}
- mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront");
+ mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront",
+ false /* forceNonResizable */);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -17620,7 +17622,7 @@
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, appOp, null, serialized, sticky,
+ requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 2e9947a..837a1c1 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4776,6 +4776,7 @@
ci.numActivities = numActivities;
ci.numRunning = numRunning;
ci.isDockable = task.canGoInDockedStack();
+ ci.resizeMode = task.mResizeMode;
list.add(ci);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index d34e8fc..598d9ff 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1759,8 +1759,8 @@
}
}
- void findTaskToMoveToFrontLocked(
- TaskRecord task, int flags, ActivityOptions options, String reason) {
+ void findTaskToMoveToFrontLocked(TaskRecord task, int flags, ActivityOptions options,
+ String reason, boolean forceNonResizeable) {
if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
mUserLeaving = true;
}
@@ -1811,7 +1811,8 @@
if (DEBUG_STACK) Slog.d(TAG_STACK,
"findTaskToMoveToFront: moved to front of stack=" + task.stack);
- handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId);
+ handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+ forceNonResizeable);
}
boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
@@ -3360,19 +3361,25 @@
}
}
+ void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId, int actualStackId) {
+ handleNonResizableTaskIfNeeded(task, preferredStackId, actualStackId,
+ false /* forceNonResizable */);
+ }
+
void handleNonResizableTaskIfNeeded(
- TaskRecord task, int preferredStackId, int actualStackId) {
+ TaskRecord task, int preferredStackId, int actualStackId, boolean forceNonResizable) {
if ((!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID)
|| task.isHomeTask()) {
return;
}
- if (!task.canGoInDockedStack()) {
+ if (!task.canGoInDockedStack() || forceNonResizable) {
// Display a warning toast that we tried to put a non-dockable task in the docked stack.
mService.mHandler.sendEmptyMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG);
- // Dismiss docked stack.
- mService.moveTasksToFullscreenStack(DOCKED_STACK_ID, false);
+ // Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
+ // we need to move it to top of fullscreen stack, otherwise it will be covered.
+ mService.moveTasksToFullscreenStack(DOCKED_STACK_ID, actualStackId == DOCKED_STACK_ID);
} else if (task.mResizeMode == RESIZE_MODE_FORCE_RESIZEABLE) {
String packageName = task.getTopActivity() != null
? task.getTopActivity().appInfo.packageName : null;
@@ -3443,8 +3450,12 @@
}
if (andResume) {
- findTaskToMoveToFrontLocked(task, 0, null, reason);
+ findTaskToMoveToFrontLocked(task, 0, null, reason,
+ lockTaskModeState != LOCK_TASK_MODE_NONE);
resumeFocusedStackTopActivityLocked();
+ } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
+ handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+ true /* forceNonResizable */);
}
}
@@ -4248,6 +4259,7 @@
// Work Challenge is present) let startActivityInPackage handle the intercepting.
if (!mService.mUserController.shouldConfirmCredentials(task.userId)
&& task.getRootActivity() != null) {
+ mActivityMetricsLogger.notifyActivityLaunching();
mService.moveTaskToFrontLocked(task.taskId, 0, bOptions);
// If we are launching the task in the docked stack, put it into resizing mode so
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index bbb162e..d330756 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -120,8 +120,9 @@
/**
* Inform ConnectivityService that the network has been tested.
- * obj = NetworkAgentInfo
+ * obj = String representing URL that Internet probe was redirect to, if it was redirected.
* arg1 = One of the NETWORK_TESTED_RESULT_* constants.
+ * arg2 = NetID.
*/
public static final int EVENT_NETWORK_TESTED = BASE + 2;
@@ -334,8 +335,8 @@
mDontDisplaySigninNotification = true;
mUserDoesNotWant = true;
mConnectivityServiceHandler.sendMessage(obtainMessage(
- EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0,
- mNetworkAgentInfo));
+ EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID,
+ mNetworkAgentInfo.network.netId, null));
// TODO: Should teardown network.
mUidResponsibleForReeval = 0;
transitionTo(mEvaluatingState);
@@ -358,7 +359,7 @@
CaptivePortalStateChangeEvent.logEvent(
CaptivePortalStateChangeEvent.NETWORK_MONITOR_VALIDATED);
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
- NETWORK_TEST_RESULT_VALID, 0, mNetworkAgentInfo));
+ NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null));
}
@Override
@@ -412,6 +413,21 @@
}
}
+ /**
+ * Result of calling isCaptivePortal().
+ * @hide
+ */
+ @VisibleForTesting
+ public static final class CaptivePortalProbeResult {
+ final int mHttpResponseCode; // HTTP response code returned from Internet probe.
+ final String mRedirectUrl; // Redirect destination returned from Internet probe.
+
+ public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl) {
+ mHttpResponseCode = httpResponseCode;
+ mRedirectUrl = redirectUrl;
+ }
+ }
+
// Being in the EvaluatingState State indicates the Network is being evaluated for internet
// connectivity, or that the user has indicated that this network is unwanted.
private class EvaluatingState extends State {
@@ -464,19 +480,23 @@
// IPv6) could each take SOCKET_TIMEOUT_MS. During this time this StateMachine
// will be unresponsive. isCaptivePortal() could be executed on another Thread
// if this is found to cause problems.
- int httpResponseCode = isCaptivePortal();
+ CaptivePortalProbeResult probeResult = isCaptivePortal();
CaptivePortalCheckResultEvent.logEvent(mNetworkAgentInfo.network.netId,
- httpResponseCode);
- if (httpResponseCode == 204) {
+ probeResult.mHttpResponseCode);
+ if (probeResult.mHttpResponseCode == 204) {
transitionTo(mValidatedState);
- } else if (httpResponseCode >= 200 && httpResponseCode <= 399) {
+ } else if (probeResult.mHttpResponseCode >= 200 &&
+ probeResult.mHttpResponseCode <= 399) {
+ mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
+ NETWORK_TEST_RESULT_INVALID, mNetworkAgentInfo.network.netId,
+ probeResult.mRedirectUrl));
transitionTo(mCaptivePortalState);
} else {
final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
sendMessageDelayed(msg, mReevaluateDelayMs);
mConnectivityServiceHandler.sendMessage(obtainMessage(
- EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0,
- mNetworkAgentInfo));
+ EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID,
+ mNetworkAgentInfo.network.netId, probeResult.mRedirectUrl));
if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
// Don't continue to blame UID forever.
TrafficStats.clearThreadStatsUid();
@@ -533,8 +553,6 @@
@Override
public void enter() {
- mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
- NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo));
// Don't annoy user with sign-in notifications.
if (mDontDisplaySigninNotification) return;
// Create a CustomIntentReceiver that sends us a
@@ -639,11 +657,12 @@
* Returns HTTP response code.
*/
@VisibleForTesting
- protected int isCaptivePortal() {
- if (!mIsCaptivePortalCheckEnabled) return 204;
+ protected CaptivePortalProbeResult isCaptivePortal() {
+ if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204, null);
HttpURLConnection urlConnection = null;
int httpResponseCode = 599;
+ String redirectUrl = null;
try {
URL url = new URL(getCaptivePortalServerUrl(mContext));
// On networks with a PAC instead of fetching a URL that should result in a 204
@@ -699,6 +718,7 @@
long requestTimestamp = SystemClock.elapsedRealtime();
httpResponseCode = urlConnection.getResponseCode();
+ redirectUrl = urlConnection.getHeaderField("location");
// Time how long it takes to get a response to our request
long responseTimestamp = SystemClock.elapsedRealtime();
@@ -739,7 +759,7 @@
urlConnection.disconnect();
}
}
- return httpResponseCode;
+ return new CaptivePortalProbeResult(httpResponseCode, redirectUrl);
}
/**
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 6e7ea99..03eb019 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -77,7 +77,7 @@
static final boolean DEBUG = false;
public static class Lifecycle extends SystemService {
- private ContentService mContentService;
+ private ContentService mService;
public Lifecycle(Context context) {
super(context);
@@ -87,14 +87,21 @@
public void onStart() {
final boolean factoryTest = (FactoryTest
.getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL);
- mContentService = new ContentService(getContext(), factoryTest);
- publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mContentService);
+ mService = new ContentService(getContext(), factoryTest);
+ publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mService.systemReady();
+ }
}
@Override
public void onCleanupUser(int userHandle) {
- synchronized (mContentService.mCache) {
- mContentService.mCache.remove(userHandle);
+ synchronized (mService.mCache) {
+ mService.mCache.remove(userHandle);
}
}
}
@@ -265,7 +272,7 @@
localeFilter, null, null);
}
- public void systemReady() {
+ void systemReady() {
getSyncManager();
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index db41a54..8af0af0 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1402,24 +1402,12 @@
}
}
- private void restoreLostPeriodicSyncsIfNeeded(int userId) {
- List<SyncOperation> periodicSyncs = new ArrayList<SyncOperation>();
- for (SyncOperation sync : getAllPendingSyncs()) {
- if (sync.isPeriodic && sync.target.userId == userId) {
- periodicSyncs.add(sync);
- }
- }
- mSyncStorageEngine.restorePeriodicSyncsIfNeededForUser(userId, periodicSyncs);
- }
-
private void onUserUnlocked(int userId) {
// Make sure that accounts we're about to use are valid.
AccountManagerService.getSingleton().validateAccounts(userId);
mSyncAdapters.invalidateCache(userId);
- restoreLostPeriodicSyncsIfNeeded(userId);
-
EndPoint target = new EndPoint(null, null, userId);
updateRunningAccounts(target);
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index fb23265..bc3fc6a 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -826,35 +826,6 @@
return true;
}
- /**
- * STOPSHIP This is a temporary workaround and should be removed before shipping: b/28052438
- */
- void restorePeriodicSyncsIfNeededForUser(int userHandle, List<SyncOperation> periodicSyncs) {
- if (mPeriodicSyncAddedListener == null) {
- return;
- }
- synchronized (mAuthorities) {
- for (int i = 0; i < mAuthorities.size(); i++) {
- AuthorityInfo authority = mAuthorities.valueAt(i);
- if (authority.target.userId == userHandle && authority.enabled) {
- boolean periodicSyncAlreadyExists = false;
- for (SyncOperation sync : periodicSyncs) {
- if (authority.target.matchesSpec(sync.target)) {
- periodicSyncAlreadyExists = true;
- break;
- }
- }
- // The periodic sync must have been lost due to previous bug.
- if (!periodicSyncAlreadyExists) {
- mPeriodicSyncAddedListener.onPeriodicSyncAdded(authority.target,
- new Bundle(), DEFAULT_POLL_FREQUENCY_SECONDS,
- calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS));
- }
- }
- }
- }
- }
-
public void setMasterSyncAutomatically(boolean flag, int userId) {
synchronized (mAuthorities) {
Boolean auto = mMasterSyncAutomatically.get(userId);
diff --git a/services/core/java/com/android/server/job/JobPackageTracker.java b/services/core/java/com/android/server/job/JobPackageTracker.java
new file mode 100644
index 0000000..e5a2095
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobPackageTracker.java
@@ -0,0 +1,361 @@
+/*
+ * 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
+ */
+
+package com.android.server.job;
+
+import android.app.job.JobInfo;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+import com.android.server.job.controllers.JobStatus;
+
+import java.io.PrintWriter;
+
+public final class JobPackageTracker {
+ // We batch every 30 minutes.
+ static final long BATCHING_TIME = 30*60*1000;
+ // Number of historical data sets we keep.
+ static final int NUM_HISTORY = 5;
+
+ DataSet mCurDataSet = new DataSet();
+ DataSet[] mLastDataSets = new DataSet[NUM_HISTORY];
+
+ final static class PackageEntry {
+ long pastActiveTime;
+ long activeStartTime;
+ int activeCount;
+ boolean hadActive;
+ long pastActiveTopTime;
+ long activeTopStartTime;
+ int activeTopCount;
+ boolean hadActiveTop;
+ long pastPendingTime;
+ long pendingStartTime;
+ int pendingCount;
+ boolean hadPending;
+
+ public long getActiveTime(long now) {
+ long time = pastActiveTime;
+ if (activeCount > 0) {
+ time += now - activeStartTime;
+ }
+ return time;
+ }
+
+ public long getActiveTopTime(long now) {
+ long time = pastActiveTopTime;
+ if (activeTopCount > 0) {
+ time += now - activeTopStartTime;
+ }
+ return time;
+ }
+
+ public long getPendingTime(long now) {
+ long time = pastPendingTime;
+ if (pendingCount > 0) {
+ time += now - pendingStartTime;
+ }
+ return time;
+ }
+ }
+
+ final static class DataSet {
+ final SparseArray<ArrayMap<String, PackageEntry>> mEntries = new SparseArray<>();
+ final long mStartUptimeTime;
+ final long mStartElapsedTime;
+ final long mStartClockTime;
+ long mSummedTime;
+
+ public DataSet(DataSet otherTimes) {
+ mStartUptimeTime = otherTimes.mStartUptimeTime;
+ mStartElapsedTime = otherTimes.mStartElapsedTime;
+ mStartClockTime = otherTimes.mStartClockTime;
+ }
+
+ public DataSet() {
+ mStartUptimeTime = SystemClock.uptimeMillis();
+ mStartElapsedTime = SystemClock.elapsedRealtime();
+ mStartClockTime = System.currentTimeMillis();
+ }
+
+ private PackageEntry getOrCreateEntry(int uid, String pkg) {
+ ArrayMap<String, PackageEntry> uidMap = mEntries.get(uid);
+ if (uidMap == null) {
+ uidMap = new ArrayMap<>();
+ mEntries.put(uid, uidMap);
+ }
+ PackageEntry entry = uidMap.get(pkg);
+ if (entry == null) {
+ entry = new PackageEntry();
+ uidMap.put(pkg, entry);
+ }
+ return entry;
+ }
+
+ public PackageEntry getEntry(int uid, String pkg) {
+ ArrayMap<String, PackageEntry> uidMap = mEntries.get(uid);
+ if (uidMap == null) {
+ return null;
+ }
+ return uidMap.get(pkg);
+ }
+
+ long getTotalTime(long now) {
+ if (mSummedTime > 0) {
+ return mSummedTime;
+ }
+ return now - mStartUptimeTime;
+ }
+
+ void incPending(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.pendingCount == 0) {
+ pe.pendingStartTime = now;
+ }
+ pe.pendingCount++;
+ }
+
+ void decPending(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.pendingCount == 1) {
+ pe.pastPendingTime += now - pe.pendingStartTime;
+ }
+ pe.pendingCount--;
+ }
+
+ void incActive(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.activeCount == 0) {
+ pe.activeStartTime = now;
+ }
+ pe.activeCount++;
+ }
+
+ void decActive(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.activeCount == 1) {
+ pe.pastActiveTime += now - pe.activeStartTime;
+ }
+ pe.activeCount--;
+ }
+
+ void incActiveTop(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.activeTopCount == 0) {
+ pe.activeTopStartTime = now;
+ }
+ pe.activeTopCount++;
+ }
+
+ void decActiveTop(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.activeTopCount == 1) {
+ pe.pastActiveTopTime += now - pe.activeTopStartTime;
+ }
+ pe.activeTopCount--;
+ }
+
+ void finish(DataSet next, long now) {
+ for (int i = mEntries.size() - 1; i >= 0; i--) {
+ ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+ for (int j = uidMap.size() - 1; j >= 0; j--) {
+ PackageEntry pe = uidMap.valueAt(j);
+ if (pe.activeCount > 0 || pe.activeTopCount > 0 || pe.pendingCount > 0) {
+ // Propagate existing activity in to next data set.
+ PackageEntry nextPe = next.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j));
+ nextPe.activeStartTime = now;
+ nextPe.activeCount = pe.activeCount;
+ nextPe.activeTopStartTime = now;
+ nextPe.activeTopCount = pe.activeTopCount;
+ nextPe.pendingStartTime = now;
+ nextPe.pendingCount = pe.pendingCount;
+ // Finish it off.
+ if (pe.activeCount > 0) {
+ pe.pastActiveTime += now - pe.activeStartTime;
+ pe.activeCount = 0;
+ }
+ if (pe.activeTopCount > 0) {
+ pe.pastActiveTopTime += now - pe.activeTopStartTime;
+ pe.activeTopCount = 0;
+ }
+ if (pe.pendingCount > 0) {
+ pe.pastPendingTime += now - pe.pendingStartTime;
+ pe.pendingCount = 0;
+ }
+ }
+ }
+ }
+ }
+
+ void addTo(DataSet out, long now) {
+ out.mSummedTime += getTotalTime(now);
+ for (int i = mEntries.size() - 1; i >= 0; i--) {
+ ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+ for (int j = uidMap.size() - 1; j >= 0; j--) {
+ PackageEntry pe = uidMap.valueAt(j);
+ PackageEntry outPe = out.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j));
+ outPe.pastActiveTime += pe.pastActiveTime;
+ outPe.pastActiveTopTime += pe.pastActiveTopTime;
+ outPe.pastPendingTime += pe.pastPendingTime;
+ if (pe.activeCount > 0) {
+ outPe.pastActiveTime += now - pe.activeStartTime;
+ outPe.hadActive = true;
+ }
+ if (pe.activeTopCount > 0) {
+ outPe.pastActiveTopTime += now - pe.activeTopStartTime;
+ outPe.hadActiveTop = true;
+ }
+ if (pe.pendingCount > 0) {
+ outPe.pastPendingTime += now - pe.pendingStartTime;
+ outPe.hadPending = true;
+ }
+ }
+ }
+ }
+
+ void printDuration(PrintWriter pw, long period, long duration, String suffix) {
+ float fraction = duration / (float) period;
+ int percent = (int) ((fraction * 100) + .5f);
+ if (percent > 0) {
+ pw.print(" ");
+ pw.print(percent);
+ pw.print("% ");
+ pw.print(suffix);
+ }
+ }
+
+ void dump(PrintWriter pw, String header, String prefix, long now, long nowEllapsed) {
+ final long period = getTotalTime(now);
+ pw.print(prefix); pw.print(header); pw.print(" at ");
+ pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", mStartClockTime).toString());
+ pw.print(" (");
+ TimeUtils.formatDuration(mStartElapsedTime, nowEllapsed, pw);
+ pw.print(") over ");
+ TimeUtils.formatDuration(period, pw);
+ pw.println(":");
+ final int NE = mEntries.size();
+ for (int i = 0; i < NE; i++) {
+ ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+ final int NP = uidMap.size();
+ for (int j = 0; j < NP; j++) {
+ PackageEntry pe = uidMap.valueAt(j);
+ pw.print(prefix); pw.print(" ");
+ UserHandle.formatUid(pw, mEntries.keyAt(i));
+ pw.print(" / "); pw.print(uidMap.keyAt(j));
+ pw.print(":");
+ printDuration(pw, period, pe.getPendingTime(now), "pending");
+ printDuration(pw, period, pe.getActiveTime(now), "active");
+ printDuration(pw, period, pe.getActiveTopTime(now), "active-top");
+ if (pe.pendingCount > 0 || pe.hadPending) {
+ pw.print(" (pending)");
+ }
+ if (pe.activeCount > 0 || pe.hadActive) {
+ pw.print(" (active)");
+ }
+ if (pe.activeTopCount > 0 || pe.hadActiveTop) {
+ pw.print(" (active-top)");
+ }
+ pw.println();
+ }
+ }
+ }
+ }
+
+ void rebatchIfNeeded(long now) {
+ long totalTime = mCurDataSet.getTotalTime(now);
+ if (totalTime > BATCHING_TIME) {
+ DataSet last = mCurDataSet;
+ last.mSummedTime = totalTime;
+ mCurDataSet = new DataSet();
+ last.finish(mCurDataSet, now);
+ System.arraycopy(mLastDataSets, 0, mLastDataSets, 1, mLastDataSets.length-1);
+ mLastDataSets[0] = last;
+ }
+ }
+
+ public void notePending(JobStatus job) {
+ final long now = SystemClock.uptimeMillis();
+ rebatchIfNeeded(now);
+ mCurDataSet.incPending(job.getSourceUid(), job.getSourcePackageName(), now);
+ }
+
+ public void noteNonpending(JobStatus job) {
+ final long now = SystemClock.uptimeMillis();
+ mCurDataSet.decPending(job.getSourceUid(), job.getSourcePackageName(), now);
+ rebatchIfNeeded(now);
+ }
+
+ public void noteActive(JobStatus job) {
+ final long now = SystemClock.uptimeMillis();
+ rebatchIfNeeded(now);
+ if (job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
+ mCurDataSet.incActiveTop(job.getSourceUid(), job.getSourcePackageName(), now);
+ } else {
+ mCurDataSet.incActive(job.getSourceUid(), job.getSourcePackageName(), now);
+ }
+ }
+
+ public void noteInactive(JobStatus job) {
+ final long now = SystemClock.uptimeMillis();
+ if (job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
+ mCurDataSet.decActiveTop(job.getSourceUid(), job.getSourcePackageName(), now);
+ } else {
+ mCurDataSet.decActive(job.getSourceUid(), job.getSourcePackageName(), now);
+ }
+ rebatchIfNeeded(now);
+ }
+
+ public float getLoadFactor(JobStatus job) {
+ final int uid = job.getSourceUid();
+ final String pkg = job.getSourcePackageName();
+ PackageEntry cur = mCurDataSet.getEntry(uid, pkg);
+ PackageEntry last = mLastDataSets[0] != null ? mLastDataSets[0].getEntry(uid, pkg) : null;
+ if (cur == null && last == null) {
+ return 0;
+ }
+ final long now = SystemClock.uptimeMillis();
+ long time = cur.getActiveTime(now) + cur.getPendingTime(now);
+ long period = mCurDataSet.getTotalTime(now);
+ if (last != null) {
+ time += last.getActiveTime(now) + last.getPendingTime(now);
+ period += mLastDataSets[0].getTotalTime(now);
+ }
+ return time / (float)period;
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ final long now = SystemClock.uptimeMillis();
+ final long nowEllapsed = SystemClock.elapsedRealtime();
+ final DataSet total;
+ if (mLastDataSets[0] != null) {
+ total = new DataSet(mLastDataSets[0]);
+ mLastDataSets[0].addTo(total, now);
+ } else {
+ total = new DataSet(mCurDataSet);
+ }
+ mCurDataSet.addTo(total, now);
+ for (int i = 1; i < mLastDataSets.length; i++) {
+ if (mLastDataSets[i] != null) {
+ mLastDataSets[i].dump(pw, "Historical stats", prefix, now, nowEllapsed);
+ pw.println();
+ }
+ }
+ total.dump(pw, "Current stats", prefix, now, nowEllapsed);
+ }
+}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index b235002..7df8ffd 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -93,16 +93,24 @@
public static final boolean DEBUG = false;
/** The maximum number of concurrent jobs we run at one time. */
- private static final int MAX_JOB_CONTEXTS_COUNT = 8;
+ private static final int MAX_JOB_CONTEXTS_COUNT = 12;
+ /** The number of MAX_JOB_CONTEXTS_COUNT we reserve for the foreground app. */
+ private static final int FG_JOB_CONTEXTS_COUNT = 4;
/** Enforce a per-app limit on scheduled jobs? */
private static final boolean ENFORCE_MAX_JOBS = true;
/** The maximum number of jobs that we allow an unprivileged app to schedule */
private static final int MAX_JOBS_PER_APP = 100;
+ /** This is the job execution factor that is considered to be heavy use of the system. */
+ private static final float HEAVY_USE_FACTOR = .9f;
+ /** This is the job execution factor that is considered to be moderate use of the system. */
+ private static final float MODERATE_USE_FACTOR = .5f;
/** Global local for all job scheduler state. */
final Object mLock = new Object();
/** Master list of jobs. */
final JobStore mJobs;
+ /** Tracking amount of time each package runs for. */
+ final JobPackageTracker mJobPackageTracker = new JobPackageTracker();
static final int MSG_JOB_EXPIRED = 0;
static final int MSG_CHECK_JOB = 1;
@@ -173,7 +181,7 @@
* Current limit on the number of concurrent JobServiceContext entries we want to
* keep actively running a job.
*/
- int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+ int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT;
/**
* Which uids are currently in the foreground.
@@ -249,6 +257,10 @@
return mLock;
}
+ public JobStore getJobStore() {
+ return mJobs;
+ }
+
@Override
public void onStartUser(int userHandle) {
mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userHandle);
@@ -386,7 +398,9 @@
stopTrackingJob(cancelled, incomingJob, true /* writeBack */);
synchronized (mLock) {
// Remove from pending queue.
- mPendingJobs.remove(cancelled);
+ if (mPendingJobs.remove(cancelled)) {
+ mJobPackageTracker.noteNonpending(cancelled);
+ }
// Cancel if running.
stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED);
reportActive();
@@ -518,7 +532,7 @@
// Create the "runners".
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
mActiveServices.add(
- new JobServiceContext(this, mBatteryStats,
+ new JobServiceContext(this, mBatteryStats, mJobPackageTracker,
getContext().getMainLooper()));
}
// Attach jobs to their controllers.
@@ -604,6 +618,20 @@
return false;
}
+ void noteJobsPending(List<JobStatus> jobs) {
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ JobStatus job = jobs.get(i);
+ mJobPackageTracker.notePending(job);
+ }
+ }
+
+ void noteJobsNonpending(List<JobStatus> jobs) {
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ JobStatus job = jobs.get(i);
+ mJobPackageTracker.noteNonpending(job);
+ }
+ }
+
/**
* Reschedules the given job based on the job's backoff policy. It doesn't make sense to
* specify an override deadline on a failed job (the failed job will run even though it's not
@@ -759,6 +787,7 @@
// state is such that all ready jobs should be run immediately.
if (runNow != null && !mPendingJobs.contains(runNow)
&& mJobs.containsJob(runNow)) {
+ mJobPackageTracker.notePending(runNow);
mPendingJobs.add(runNow);
}
queueReadyJobsForExecutionLockedH();
@@ -797,6 +826,7 @@
if (DEBUG) {
Slog.d(TAG, "queuing all ready jobs for execution:");
}
+ noteJobsNonpending(mPendingJobs);
mPendingJobs.clear();
mJobs.forEachJob(mReadyQueueFunctor);
mReadyQueueFunctor.postProcess();
@@ -832,6 +862,7 @@
public void postProcess() {
if (newReadyJobs != null) {
+ noteJobsPending(newReadyJobs);
mPendingJobs.addAll(newReadyJobs);
}
newReadyJobs = null;
@@ -910,6 +941,7 @@
if (DEBUG) {
Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs.");
}
+ noteJobsPending(runnableJobs);
mPendingJobs.addAll(runnableJobs);
} else {
if (DEBUG) {
@@ -935,6 +967,7 @@
private void maybeQueueReadyJobsForExecutionLockedH() {
if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");
+ noteJobsNonpending(mPendingJobs);
mPendingJobs.clear();
mJobs.forEachJob(mMaybeQueueFunctor);
mMaybeQueueFunctor.postProcess();
@@ -998,16 +1031,28 @@
}
}
+ private int adjustJobPriority(int curPriority, JobStatus job) {
+ if (curPriority < JobInfo.PRIORITY_TOP_APP) {
+ float factor = mJobPackageTracker.getLoadFactor(job);
+ if (factor >= HEAVY_USE_FACTOR) {
+ curPriority += JobInfo.PRIORITY_ADJ_ALWAYS_RUNNING;
+ } else if (factor >= MODERATE_USE_FACTOR) {
+ curPriority += JobInfo.PRIORITY_ADJ_OFTEN_RUNNING;
+ }
+ }
+ return curPriority;
+ }
+
private int evaluateJobPriorityLocked(JobStatus job) {
int priority = job.getPriority();
if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) {
- return priority;
+ return adjustJobPriority(priority, job);
}
int override = mUidPriorityOverride.get(job.getSourceUid(), 0);
if (override != 0) {
- return override;
+ return adjustJobPriority(override, job);
}
- return priority;
+ return adjustJobPriority(priority, job);
}
/**
@@ -1029,16 +1074,16 @@
}
switch (memLevel) {
case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
- mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - 2) * 2) / 3;
+ mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT) * 2) / 3;
break;
case ProcessStats.ADJ_MEM_FACTOR_LOW:
- mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - 2) / 3;
+ mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT) / 3;
break;
case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
mMaxActiveJobs = 1;
break;
default:
- mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+ mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT;
break;
}
@@ -1134,7 +1179,9 @@
if (!mActiveServices.get(i).executeRunnableJob(pendingJob)) {
Slog.d(TAG, "Error executing " + pendingJob);
}
- mPendingJobs.remove(pendingJob);
+ if (mPendingJobs.remove(pendingJob)) {
+ mJobPackageTracker.noteNonpending(pendingJob);
+ }
}
}
if (!preservePreferredUid) {
@@ -1444,6 +1491,8 @@
pw.print(": "); pw.println(mUidPriorityOverride.valueAt(i));
}
pw.println();
+ mJobPackageTracker.dump(pw, "");
+ pw.println();
pw.println("Pending queue:");
for (int i=0; i<mPendingJobs.size(); i++) {
JobStatus job = mPendingJobs.get(i);
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 4239248..4fd1350 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -105,6 +105,7 @@
private final Context mContext;
private final Object mLock;
private final IBatteryStats mBatteryStats;
+ private final JobPackageTracker mJobPackageTracker;
private PowerManager.WakeLock mWakeLock;
// Execution state.
@@ -136,16 +137,18 @@
/** Track when job will timeout. */
private long mTimeoutElapsed;
- JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats, Looper looper) {
- this(service.getContext(), service.getLock(), batteryStats, service, looper);
+ JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats,
+ JobPackageTracker tracker, Looper looper) {
+ this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper);
}
@VisibleForTesting
JobServiceContext(Context context, Object lock, IBatteryStats batteryStats,
- JobCompletedListener completedListener, Looper looper) {
+ JobPackageTracker tracker, JobCompletedListener completedListener, Looper looper) {
mContext = context;
mLock = lock;
mBatteryStats = batteryStats;
+ mJobPackageTracker = tracker;
mCallbackHandler = new JobServiceHandler(looper);
mCompletedListener = completedListener;
mAvailable = true;
@@ -208,6 +211,7 @@
} catch (RemoteException e) {
// Whatever.
}
+ mJobPackageTracker.noteActive(job);
mAvailable = false;
return true;
}
@@ -580,6 +584,7 @@
return;
}
completedJob = mRunningJob;
+ mJobPackageTracker.noteInactive(completedJob);
try {
mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(),
mRunningJob.getSourceUid());
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index d8490d4..02bc36ca 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -22,6 +22,7 @@
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobStore;
import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
@@ -41,10 +42,52 @@
// Singleton factory
private static Object sCreationLock = new Object();
private static volatile AppIdleController sController;
- final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
+ private final JobSchedulerService mJobSchedulerService;
private final UsageStatsManagerInternal mUsageStatsInternal;
boolean mAppIdleParoleOn;
+ final class GlobalUpdateFunc implements JobStore.JobStatusFunctor {
+ boolean mChanged;
+
+ @Override public void process(JobStatus jobStatus) {
+ String packageName = jobStatus.getSourcePackageName();
+ final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
+ jobStatus.getSourceUid(), jobStatus.getSourceUserId());
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
+ }
+ if (jobStatus.setAppNotIdleConstraintSatisfied(!appIdle)) {
+ mChanged = true;
+ }
+ }
+ };
+
+ final static class PackageUpdateFunc implements JobStore.JobStatusFunctor {
+ final int mUserId;
+ final String mPackage;
+ final boolean mIdle;
+ boolean mChanged;
+
+ PackageUpdateFunc(int userId, String pkg, boolean idle) {
+ mUserId = userId;
+ mPackage = pkg;
+ mIdle = idle;
+ }
+
+ @Override public void process(JobStatus jobStatus) {
+ if (jobStatus.getSourcePackageName().equals(mPackage)
+ && jobStatus.getSourceUserId() == mUserId) {
+ if (jobStatus.setAppNotIdleConstraintSatisfied(!mIdle)) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
+ + mPackage + " to " + mIdle);
+ }
+ mChanged = true;
+ }
+ }
+ }
+ };
+
public static AppIdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
if (sController == null) {
@@ -55,9 +98,9 @@
}
}
- private AppIdleController(StateChangedListener stateChangedListener, Context context,
- Object lock) {
- super(stateChangedListener, context, lock);
+ private AppIdleController(JobSchedulerService service, Context context, Object lock) {
+ super(service, context, lock);
+ mJobSchedulerService = service;
mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
@@ -65,7 +108,6 @@
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
- mTrackedTasks.add(jobStatus);
String packageName = jobStatus.getSourcePackageName();
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
jobStatus.getSourceUid(), jobStatus.getSourceUserId());
@@ -78,19 +120,20 @@
@Override
public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) {
- mTrackedTasks.remove(jobStatus);
}
@Override
- public void dumpControllerStateLocked(PrintWriter pw) {
+ public void dumpControllerStateLocked(final PrintWriter pw) {
pw.println("AppIdle");
pw.println("Parole On: " + mAppIdleParoleOn);
- for (JobStatus task : mTrackedTasks) {
- pw.print(task.getSourcePackageName());
- pw.print(":runnable="
- + ((task.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0));
- pw.print(", ");
- }
+ mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
+ @Override public void process(JobStatus jobStatus) {
+ pw.print(" ");
+ pw.print(jobStatus.getSourcePackageName());
+ pw.print(": runnable=");
+ pw.println((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0);
+ }
+ });
pw.println();
}
@@ -102,16 +145,10 @@
return;
}
mAppIdleParoleOn = isAppIdleParoleOn;
- for (JobStatus task : mTrackedTasks) {
- String packageName = task.getSourcePackageName();
- final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
- task.getSourceUid(), task.getSourceUserId());
- if (DEBUG) {
- Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
- }
- if (task.setAppNotIdleConstraintSatisfied(!appIdle)) {
- changed = true;
- }
+ GlobalUpdateFunc update = new GlobalUpdateFunc();
+ mJobSchedulerService.getJobStore().forEachJob(update);
+ if (update.mChanged) {
+ changed = true;
}
}
if (changed) {
@@ -128,17 +165,10 @@
if (mAppIdleParoleOn) {
return;
}
- for (JobStatus task : mTrackedTasks) {
- if (task.getSourcePackageName().equals(packageName)
- && task.getSourceUserId() == userId) {
- if (task.setAppNotIdleConstraintSatisfied(!idle)) {
- if (DEBUG) {
- Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
- + packageName + " to " + idle);
- }
- changed = true;
- }
- }
+ PackageUpdateFunc update = new PackageUpdateFunc(userId, packageName, idle);
+ mJobSchedulerService.getJobStore().forEachJob(update);
+ if (update.mChanged) {
+ changed = true;
}
}
if (changed) {
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index b2f1958..c5b1a3d 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -21,6 +21,7 @@
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
+import android.util.TimeUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -46,12 +47,17 @@
*/
private static final int MAX_URIS_REPORTED = 50;
+ /**
+ * At this point we consider it urgent to schedule the job ASAP.
+ */
+ private static final int URIS_URGENT_THRESHOLD = 40;
+
private static final Object sCreationLock = new Object();
private static volatile ContentObserverController sController;
final private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
ArrayMap<Uri, ObserverInstance> mObservers = new ArrayMap<>();
- final Handler mHandler = new Handler();
+ final Handler mHandler;
public static ContentObserverController get(JobSchedulerService taskManagerService) {
synchronized (sCreationLock) {
@@ -72,6 +78,7 @@
private ContentObserverController(StateChangedListener stateChangedListener, Context context,
Object lock) {
super(stateChangedListener, context, lock);
+ mHandler = new Handler(context.getMainLooper());
}
@Override
@@ -113,6 +120,11 @@
taskStatus.changedUris = null;
taskStatus.setContentTriggerConstraintSatisfied(havePendingUris);
}
+ if (lastJob != null && lastJob.contentObserverJobInstance != null) {
+ // And now we can detach the instance state from the last job.
+ lastJob.contentObserverJobInstance.detachLocked();
+ lastJob.contentObserverJobInstance = null;
+ }
}
@Override
@@ -133,30 +145,33 @@
boolean forUpdate) {
if (taskStatus.hasContentTriggerConstraint()) {
if (taskStatus.contentObserverJobInstance != null) {
- if (incomingJob != null && taskStatus.contentObserverJobInstance != null
- && taskStatus.contentObserverJobInstance.mChangedAuthorities != null) {
- // We are stopping this job, but it is going to be replaced by this given
- // incoming job. We want to propagate our state over to it, so we don't
- // lose any content changes that had happend since the last one started.
- // If there is a previous job associated with the new job, propagate over
- // any pending content URI trigger reports.
- if (incomingJob.contentObserverJobInstance == null) {
- incomingJob.contentObserverJobInstance = new JobInstance(incomingJob);
+ taskStatus.contentObserverJobInstance.unscheduleLocked();
+ if (incomingJob != null) {
+ if (taskStatus.contentObserverJobInstance != null
+ && taskStatus.contentObserverJobInstance.mChangedAuthorities != null) {
+ // We are stopping this job, but it is going to be replaced by this given
+ // incoming job. We want to propagate our state over to it, so we don't
+ // lose any content changes that had happend since the last one started.
+ // If there is a previous job associated with the new job, propagate over
+ // any pending content URI trigger reports.
+ if (incomingJob.contentObserverJobInstance == null) {
+ incomingJob.contentObserverJobInstance = new JobInstance(incomingJob);
+ }
+ incomingJob.contentObserverJobInstance.mChangedAuthorities
+ = taskStatus.contentObserverJobInstance.mChangedAuthorities;
+ incomingJob.contentObserverJobInstance.mChangedUris
+ = taskStatus.contentObserverJobInstance.mChangedUris;
+ taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
+ taskStatus.contentObserverJobInstance.mChangedUris = null;
}
- incomingJob.contentObserverJobInstance.mChangedAuthorities
- = taskStatus.contentObserverJobInstance.mChangedAuthorities;
- incomingJob.contentObserverJobInstance.mChangedUris
- = taskStatus.contentObserverJobInstance.mChangedUris;
- taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
- taskStatus.contentObserverJobInstance.mChangedUris = null;
+ // We won't detach the content observers here, because we want to
+ // allow them to continue monitoring so we don't miss anything... and
+ // since we are giving an incomingJob here, we know this will be
+ // immediately followed by a start tracking of that job.
} else {
- // We won't do this reset if being called for an update, because
- // we know it will be immediately followed by maybeStartTrackingJobLocked...
- // and we don't want to lose any content changes in-between.
- if (taskStatus.contentObserverJobInstance != null) {
- taskStatus.contentObserverJobInstance.detach();
- taskStatus.contentObserverJobInstance = null;
- }
+ // But here there is no incomingJob, so nothing coming up, so time to detach.
+ taskStatus.contentObserverJobInstance.detachLocked();
+ taskStatus.contentObserverJobInstance = null;
}
}
mTrackedTasks.remove(taskStatus);
@@ -177,9 +192,9 @@
}
}
- class ObserverInstance extends ContentObserver {
+ final class ObserverInstance extends ContentObserver {
final Uri mUri;
- final ArrayList<JobInstance> mJobs = new ArrayList<>();
+ final ArraySet<JobInstance> mJobs = new ArraySet<>();
public ObserverInstance(Handler handler, Uri uri) {
super(handler);
@@ -188,11 +203,10 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
- boolean reportChange = false;
synchronized (mLock) {
final int N = mJobs.size();
for (int i=0; i<N; i++) {
- JobInstance inst = mJobs.get(i);
+ JobInstance inst = mJobs.valueAt(i);
if (inst.mChangedUris == null) {
inst.mChangedUris = new ArraySet<>();
}
@@ -203,26 +217,38 @@
inst.mChangedAuthorities = new ArraySet<>();
}
inst.mChangedAuthorities.add(uri.getAuthority());
- if (inst.mJobStatus.setContentTriggerConstraintSatisfied(true)) {
- reportChange = true;
- }
+ inst.scheduleLocked();
}
}
- // Let the scheduler know that state has changed. This may or may not result in an
- // execution.
- if (reportChange) {
- mStateChangedListener.onControllerStateChanged();
- }
}
}
- class JobInstance extends ArrayList<ObserverInstance> {
- private final JobStatus mJobStatus;
- private ArraySet<Uri> mChangedUris;
- private ArraySet<String> mChangedAuthorities;
+ static final class TriggerRunnable implements Runnable {
+ final JobInstance mInstance;
+
+ TriggerRunnable(JobInstance instance) {
+ mInstance = instance;
+ }
+
+ @Override public void run() {
+ mInstance.trigger();
+ }
+ }
+
+ final class JobInstance {
+ final ArrayList<ObserverInstance> mMyObservers = new ArrayList<>();
+ final JobStatus mJobStatus;
+ final Runnable mExecuteRunner;
+ final Runnable mTimeoutRunner;
+ ArraySet<Uri> mChangedUris;
+ ArraySet<String> mChangedAuthorities;
+
+ boolean mTriggerPending;
JobInstance(JobStatus jobStatus) {
mJobStatus = jobStatus;
+ mExecuteRunner = new TriggerRunnable(this);
+ mTimeoutRunner = new TriggerRunnable(this);
final JobInfo.TriggerContentUri[] uris = jobStatus.getJob().getTriggerContentUris();
if (uris != null) {
for (JobInfo.TriggerContentUri uri : uris) {
@@ -238,15 +264,54 @@
obs);
}
obs.mJobs.add(this);
- add(obs);
+ mMyObservers.add(obs);
}
}
}
- void detach() {
- final int N = size();
+ void trigger() {
+ boolean reportChange = false;
+ synchronized (mLock) {
+ if (mTriggerPending) {
+ if (mJobStatus.setContentTriggerConstraintSatisfied(true)) {
+ reportChange = true;
+ }
+ unscheduleLocked();
+ }
+ }
+ // Let the scheduler know that state has changed. This may or may not result in an
+ // execution.
+ if (reportChange) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ }
+
+ void scheduleLocked() {
+ if (!mTriggerPending) {
+ mTriggerPending = true;
+ mHandler.postDelayed(mTimeoutRunner, mJobStatus.getTriggerContentMaxDelay());
+ }
+ mHandler.removeCallbacks(mExecuteRunner);
+ if (mChangedUris.size() >= URIS_URGENT_THRESHOLD) {
+ // If we start getting near the limit, GO NOW!
+ mHandler.post(mExecuteRunner);
+ } else {
+ mHandler.postDelayed(mExecuteRunner, mJobStatus.getTriggerContentUpdateDelay());
+ }
+ }
+
+ void unscheduleLocked() {
+ if (mTriggerPending) {
+ mHandler.removeCallbacks(mExecuteRunner);
+ mHandler.removeCallbacks(mTimeoutRunner);
+ mTriggerPending = false;
+ }
+ }
+
+ void detachLocked() {
+ final int N = mMyObservers.size();
for (int i=0; i<N; i++) {
- final ObserverInstance obs = get(i);
+ final ObserverInstance obs = mMyObservers.get(i);
obs.mJobs.remove(this);
if (obs.mJobs.size() == 0) {
mContext.getContentResolver().unregisterContentObserver(obs);
@@ -259,39 +324,54 @@
@Override
public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("Content.");
+ boolean printed = false;
Iterator<JobStatus> it = mTrackedTasks.iterator();
- if (it.hasNext()) {
- pw.print(String.valueOf(it.next().hashCode()));
- }
while (it.hasNext()) {
- pw.print("," + String.valueOf(it.next().hashCode()));
+ if (!printed) {
+ pw.print(" ");
+ printed = true;
+ } else {
+ pw.print(",");
+ }
+ pw.print(System.identityHashCode(it.next()));
}
- pw.println();
+ if (printed) {
+ pw.println();
+ }
int N = mObservers.size();
if (N > 0) {
- pw.println("URIs:");
+ pw.println(" Observers:");
for (int i = 0; i < N; i++) {
ObserverInstance obs = mObservers.valueAt(i);
- pw.print(" ");
- pw.print(mObservers.keyAt(i));
- pw.println(":");
pw.print(" ");
- pw.println(obs);
- pw.println(" Jobs:");
+ pw.print(mObservers.keyAt(i));
+ pw.print(" (");
+ pw.print(System.identityHashCode(obs));
+ pw.println("):");
+ pw.println(" Jobs:");
int M = obs.mJobs.size();
for (int j=0; j<M; j++) {
- JobInstance inst = obs.mJobs.get(j);
- pw.print(" ");
- pw.print(inst.hashCode());
+ JobInstance inst = obs.mJobs.valueAt(j);
+ pw.print(" ");
+ pw.print(System.identityHashCode(inst.mJobStatus));
if (inst.mChangedAuthorities != null) {
pw.println(":");
- pw.println(" Changed Authorities:");
+ if (inst.mTriggerPending) {
+ pw.print(" Trigger pending: update=");
+ TimeUtils.formatDuration(
+ inst.mJobStatus.getTriggerContentUpdateDelay(), pw);
+ pw.print(", max=");
+ TimeUtils.formatDuration(
+ inst.mJobStatus.getTriggerContentMaxDelay(), pw);
+ pw.println();
+ }
+ pw.println(" Changed Authorities:");
for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
pw.print(" ");
pw.println(inst.mChangedAuthorities.valueAt(k));
}
if (inst.mChangedUris != null) {
- pw.println(" Changed URIs:");
+ pw.println(" Changed URIs:");
for (int k = 0; k<inst.mChangedUris.size(); k++) {
pw.print(" ");
pw.println(inst.mChangedUris.valueAt(k));
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 64887e8..fe563d2 100644
--- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -28,6 +28,7 @@
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobStore;
import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
@@ -45,9 +46,9 @@
// Singleton factory
private static Object sCreationLock = new Object();
- final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
private static DeviceIdleJobsController sController;
+ private final JobSchedulerService mJobSchedulerService;
private final PowerManager mPowerManager;
private final DeviceIdleController.LocalService mLocalDeviceIdleController;
@@ -57,6 +58,12 @@
private boolean mDeviceIdleMode;
private int[] mDeviceIdleWhitelistAppIds;
+ final JobStore.JobStatusFunctor mUpdateFunctor = new JobStore.JobStatusFunctor() {
+ @Override public void process(JobStatus jobStatus) {
+ updateTaskStateLocked(jobStatus);
+ }
+ };
+
/**
* Returns a singleton for the DeviceIdleJobsController
*/
@@ -87,10 +94,11 @@
}
};
- private DeviceIdleJobsController(StateChangedListener stateChangedListener, Context context,
+ private DeviceIdleJobsController(JobSchedulerService jobSchedulerService, Context context,
Object lock) {
- super(stateChangedListener, context, lock);
+ super(jobSchedulerService, context, lock);
+ mJobSchedulerService = jobSchedulerService;
// Register for device idle mode changes
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mLocalDeviceIdleController =
@@ -115,9 +123,7 @@
}
mDeviceIdleMode = enabled;
if (LOG_DEBUG) Slog.d(LOG_TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
- for (JobStatus task : mTrackedTasks) {
- updateTaskStateLocked(task);
- }
+ mJobSchedulerService.getJobStore().forEachJob(mUpdateFunctor);
}
// Inform the job scheduler service about idle mode changes
if (changed) {
@@ -160,25 +166,26 @@
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
synchronized (mLock) {
- mTrackedTasks.add(jobStatus);
updateTaskStateLocked(jobStatus);
}
}
@Override
public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) {
- mTrackedTasks.remove(jobStatus);
}
@Override
- public void dumpControllerStateLocked(PrintWriter pw) {
+ public void dumpControllerStateLocked(final PrintWriter pw) {
pw.println("DeviceIdleJobsController");
- for (JobStatus task : mTrackedTasks) {
- pw.print(task.getSourcePackageName());
- pw.print(":runnable="
- + ((task.satisfiedConstraints & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0));
- pw.print(", ");
- }
+ mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
+ @Override public void process(JobStatus jobStatus) {
+ pw.print(" ");
+ pw.print(jobStatus.getSourcePackageName());
+ pw.print(": runnable=");
+ pw.println((jobStatus.satisfiedConstraints
+ & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0);
+ }
+ });
pw.println();
}
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 39905d8..dd70758 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -61,6 +61,18 @@
// Full override: ignore all constraints including API-affecting like connectivity
public static final int OVERRIDE_FULL = 2;
+ /** If not specified, trigger update delay is 10 seconds. */
+ public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
+
+ /** The minimum possible update delay is 1/2 second. */
+ public static final long MIN_TRIGGER_UPDATE_DELAY = 500;
+
+ /** If not specified, trigger maxumum delay is 2 minutes. */
+ public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000;
+
+ /** The minimum possible update delay is 1 second. */
+ public static final long MIN_TRIGGER_MAX_DELAY = 1000;
+
final JobInfo job;
/** Uid of the package requesting this job. */
final int callingUid;
@@ -320,6 +332,22 @@
return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
}
+ public long getTriggerContentUpdateDelay() {
+ long time = job.getTriggerContentUpdateDelay();
+ if (time < 0) {
+ return DEFAULT_TRIGGER_UPDATE_DELAY;
+ }
+ return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
+ }
+
+ public long getTriggerContentMaxDelay() {
+ long time = job.getTriggerContentMaxDelay();
+ if (time < 0) {
+ return DEFAULT_TRIGGER_MAX_DELAY;
+ }
+ return Math.max(time, MIN_TRIGGER_MAX_DELAY);
+ }
+
public boolean isPersisted() {
return job.isPersisted();
}
@@ -540,6 +568,16 @@
pw.print(Integer.toHexString(trig.getFlags()));
pw.print(' '); pw.println(trig.getUri());
}
+ if (job.getTriggerContentUpdateDelay() >= 0) {
+ pw.print(prefix); pw.print(" Trigger update delay: ");
+ TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
+ pw.println();
+ }
+ if (job.getTriggerContentMaxDelay() >= 0) {
+ pw.print(prefix); pw.print(" Trigger max delay: ");
+ TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
+ pw.println();
+ }
}
if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index d80dc3b..6b916be 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -40,7 +40,6 @@
import android.location.IGnssStatusProvider;
import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
-import android.location.GnssNavigationMessageEvent;
import android.location.IGpsGeofenceHardware;
import android.location.ILocationManager;
import android.location.INetInitiatedListener;
@@ -1668,16 +1667,6 @@
}
/**
- * called from native code - GPS navigation message callback
- */
- private void reportNavigationMessage(GnssNavigationMessageEvent event) {
- if (event != null) {
- mGnssNavigationMessageProvider
- .onNavigationMessageAvailable(event.getNavigationMessage());
- }
- }
-
- /**
* called from native code to inform us what the GPS engine capabilities are
*/
private void setEngineCapabilities(int capabilities) {
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index c19b51f..62fe70c 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -16,7 +16,7 @@
package com.android.server.notification;
-import android.app.AutomaticZenRule;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -29,7 +29,6 @@
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
-import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -82,6 +81,7 @@
c.caption = "condition provider";
c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE;
c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES;
+ c.secondarySettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
c.bindPermission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
c.settingsAction = Settings.ACTION_CONDITION_PROVIDER_SETTINGS;
c.clientLabel = R.string.condition_provider_service_binding_label;
@@ -257,7 +257,7 @@
}
@Override
- protected ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
+ protected @NonNull ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
int userId) {
final ContentResolver cr = mContext.getContentResolver();
String settingValue = Settings.Secure.getStringForUser(
@@ -265,12 +265,17 @@
settingName,
userId);
if (TextUtils.isEmpty(settingValue))
- return null;
+ return new ArraySet<>();
String[] packages = settingValue.split(ENABLED_SERVICES_SEPARATOR);
ArraySet<ComponentName> result = new ArraySet<>(packages.length);
for (int i = 0; i < packages.length; i++) {
if (!TextUtils.isEmpty(packages[i])) {
- result.addAll(queryPackageForServices(packages[i], userId));
+ final ComponentName component = ComponentName.unflattenFromString(packages[i]);
+ if (component != null) {
+ result.addAll(queryPackageForServices(component.getPackageName(), userId));
+ } else {
+ result.addAll(queryPackageForServices(packages[i], userId));
+ }
}
}
return result;
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 6d9fed4..29e2e44 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -97,8 +97,6 @@
// List of packages in restored setting across all mUserProfiles, for quick
// filtering upon package updates.
private ArraySet<String> mRestoredPackages = new ArraySet<>();
- // State of current service categories
- private ArrayMap<String, Boolean> mCategoryEnabled = new ArrayMap<>();
// List of enabled packages that have nevertheless asked not to be run
private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
@@ -128,7 +126,8 @@
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
- if (Objects.equals(element, mConfig.secureSettingName)) {
+ if (Objects.equals(element, mConfig.secureSettingName)
+ || Objects.equals(element, mConfig.secondarySettingName)) {
String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
settingRestored(element, prevValue, newValue, getSendingUserId());
@@ -188,8 +187,8 @@
// By convention, restored settings are replicated to another settings
// entry, named similarly but with a disambiguation suffix.
- public static String restoredSettingName(Config config) {
- return config.secureSettingName + ":restored";
+ public static String restoredSettingName(String setting) {
+ return setting + ":restored";
}
// The OS has done a restore of this service's saved state. We clone it to the
@@ -199,14 +198,14 @@
public void settingRestored(String element, String oldValue, String newValue, int userid) {
if (DEBUG) Slog.d(TAG, "Restored managed service setting: " + element
+ " ovalue=" + oldValue + " nvalue=" + newValue);
- if (mConfig.secureSettingName.equals(element)) {
+ if (mConfig.secureSettingName.equals(element) ||
+ mConfig.secondarySettingName.equals(element)) {
if (element != null) {
- mRestored = null;
Settings.Secure.putStringForUser(mContext.getContentResolver(),
- restoredSettingName(mConfig),
+ restoredSettingName(element),
newValue,
userid);
- updateSettingsAccordingToInstalledServices(userid);
+ updateSettingsAccordingToInstalledServices(element, userid);
rebuildRestoredPackages();
}
}
@@ -342,65 +341,28 @@
}
}
- public void setCategoryState(String category, boolean enabled) {
- synchronized (mMutex) {
- final Boolean previous = mCategoryEnabled.put(category, enabled);
- if (!(previous == null || previous != enabled)) {
- return;
- }
-
- // State changed
- if (DEBUG) {
- Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "category " + category);
- }
-
- final int[] userIds = mUserProfiles.getCurrentProfileIds();
- for (int userId : userIds) {
- final Set<ComponentName> componentNames = queryPackageForServices(null,
- userId, category);
-
- // Disallow services not enabled in Settings
- final ArraySet<ComponentName> userComponents =
- loadComponentNamesFromSetting(mConfig.secureSettingName, userId);
- if (userComponents == null) {
- componentNames.clear();
- } else {
- componentNames.retainAll(userComponents);
- }
-
- if (DEBUG) {
- Slog.d(TAG, "Components for category " + category + ": " + componentNames);
- }
- for (ComponentName c : componentNames) {
- if (enabled) {
- registerServiceLocked(c, userId);
- } else {
- unregisterServiceLocked(c, userId);
- }
- }
- }
-
- }
- }
-
private void rebuildRestoredPackages() {
mRestoredPackages.clear();
mSnoozingForCurrentProfiles.clear();
- String settingName = restoredSettingName(mConfig);
+ String secureSettingName = restoredSettingName(mConfig.secureSettingName);
+ String secondarySettingName = mConfig.secondarySettingName == null
+ ? null : restoredSettingName(mConfig.secondarySettingName);
int[] userIds = mUserProfiles.getCurrentProfileIds();
final int N = userIds.length;
for (int i = 0; i < N; ++i) {
- ArraySet<ComponentName> names = loadComponentNamesFromSetting(settingName, userIds[i]);
- if (names == null)
- continue;
- for (ComponentName name: names) {
+ ArraySet<ComponentName> names =
+ loadComponentNamesFromSetting(secureSettingName, userIds[i]);
+ if (secondarySettingName != null) {
+ names.addAll(loadComponentNamesFromSetting(secondarySettingName, userIds[i]));
+ }
+ for (ComponentName name : names) {
mRestoredPackages.add(name.getPackageName());
}
}
}
- protected ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
+ protected @NonNull ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
int userId) {
final ContentResolver cr = mContext.getContentResolver();
String settingValue = Settings.Secure.getStringForUser(
@@ -408,7 +370,7 @@
settingName,
userId);
if (TextUtils.isEmpty(settingValue))
- return null;
+ return new ArraySet<>();
String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
ArraySet<ComponentName> result = new ArraySet<>(restored.length);
for (int i = 0; i < restored.length; i++) {
@@ -448,26 +410,22 @@
int[] userIds = mUserProfiles.getCurrentProfileIds();
final int N = userIds.length;
for (int i = 0; i < N; ++i) {
- updateSettingsAccordingToInstalledServices(userIds[i]);
+ updateSettingsAccordingToInstalledServices(mConfig.secureSettingName, userIds[i]);
+ if (mConfig.secondarySettingName != null) {
+ updateSettingsAccordingToInstalledServices(
+ mConfig.secondarySettingName, userIds[i]);
+ }
}
rebuildRestoredPackages();
}
protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
- return queryPackageForServices(packageName, userId, null);
- }
-
- public Set<ComponentName> queryPackageForServices(String packageName, int userId,
- String category) {
Set<ComponentName> installed = new ArraySet<>();
final PackageManager pm = mContext.getPackageManager();
Intent queryIntent = new Intent(mConfig.serviceInterface);
if (!TextUtils.isEmpty(packageName)) {
queryIntent.setPackage(packageName);
}
- if (category != null) {
- queryIntent.addCategory(category);
- }
List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
queryIntent,
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -493,13 +451,13 @@
return installed;
}
- private void updateSettingsAccordingToInstalledServices(int userId) {
+ private void updateSettingsAccordingToInstalledServices(String setting, int userId) {
boolean restoredChanged = false;
boolean currentChanged = false;
Set<ComponentName> restored =
- loadComponentNamesFromSetting(restoredSettingName(mConfig), userId);
+ loadComponentNamesFromSetting(restoredSettingName(setting), userId);
Set<ComponentName> current =
- loadComponentNamesFromSetting(mConfig.secureSettingName, userId);
+ loadComponentNamesFromSetting(setting, userId);
// Load all services for all packages.
Set<ComponentName> installed = queryPackageForServices(null, userId);
@@ -529,13 +487,13 @@
if (currentChanged) {
if (DEBUG) Slog.v(TAG, "List of " + getCaption() + " services was updated " + current);
- storeComponentsToSetting(retained, mConfig.secureSettingName, userId);
+ storeComponentsToSetting(retained, setting, userId);
}
if (restoredChanged) {
if (DEBUG) Slog.v(TAG,
"List of " + getCaption() + " restored services was updated " + restored);
- storeComponentsToSetting(restored, restoredSettingName(mConfig), userId);
+ storeComponentsToSetting(restored, restoredSettingName(setting), userId);
}
}
@@ -553,6 +511,10 @@
for (int i = 0; i < nUserIds; ++i) {
componentsByUser.put(userIds[i],
loadComponentNamesFromSetting(mConfig.secureSettingName, userIds[i]));
+ if (mConfig.secondarySettingName != null) {
+ componentsByUser.get(userIds[i]).addAll(
+ loadComponentNamesFromSetting(mConfig.secondarySettingName, userIds[i]));
+ }
}
final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
@@ -573,20 +535,11 @@
// decode the list of components
final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
if (null == userComponents) {
- toAdd.put(userIds[i], new HashSet<ComponentName>());
+ toAdd.put(userIds[i], new ArraySet<ComponentName>());
continue;
}
final Set<ComponentName> add = new HashSet<>(userComponents);
-
- // Remove components from disabled categories so that those services aren't run.
- for (Entry<String, Boolean> e : mCategoryEnabled.entrySet()) {
- if (!e.getValue()) {
- Set<ComponentName> c = queryPackageForServices(null, userIds[i],
- e.getKey());
- add.removeAll(c);
- }
- }
add.removeAll(mSnoozingForCurrentProfiles);
toAdd.put(userIds[i], add);
@@ -835,15 +788,25 @@
private class SettingsObserver extends ContentObserver {
private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);
+ private final Uri mSecondarySettingsUri;
private SettingsObserver(Handler handler) {
super(handler);
+ if (mConfig.secondarySettingName != null) {
+ mSecondarySettingsUri = Settings.Secure.getUriFor(mConfig.secondarySettingName);
+ } else {
+ mSecondarySettingsUri = null;
+ }
}
private void observe() {
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(mSecureSettingsUri,
false, this, UserHandle.USER_ALL);
+ if (mSecondarySettingsUri != null) {
+ resolver.registerContentObserver(mSecondarySettingsUri,
+ false, this, UserHandle.USER_ALL);
+ }
update(null);
}
@@ -853,9 +816,9 @@
}
private void update(Uri uri) {
- if (uri == null || mSecureSettingsUri.equals(uri)) {
- if (DEBUG) Slog.d(TAG, "Setting changed: mSecureSettingsUri=" + mSecureSettingsUri +
- " / uri=" + uri);
+ if (uri == null || mSecureSettingsUri.equals(uri)
+ || uri.equals(mSecondarySettingsUri)) {
+ if (DEBUG) Slog.d(TAG, "Setting changed: uri=" + uri);
rebindServices(false);
rebuildRestoredPackages();
}
@@ -977,6 +940,7 @@
public String caption;
public String serviceInterface;
public String secureSettingName;
+ public String secondarySettingName;
public String bindPermission;
public String settingsAction;
public int clientLabel;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a0f0bee..cabdced 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2009,7 +2009,7 @@
@Override
public ComponentName getEffectsSuppressor() {
enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
- return mEffectsSuppressors.get(0);
+ return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
}
@Override
@@ -2186,16 +2186,18 @@
// Clears the 'fake' auto-bunding summary.
private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
- if (adjustment.getSignals() != null
- && adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
+ if (adjustment.getSignals() != null) {
+ Bundle.setDefusable(adjustment.getSignals(), true);
+ if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
&& !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
- if (mAutobundledSummaries.containsKey(adjustment.getPackage())) {
- // Clear summary.
- final NotificationRecord removed = mNotificationsByKey.get(
- mAutobundledSummaries.remove(adjustment.getPackage()));
- if (removed != null) {
- mNotificationList.remove(removed);
- cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
+ if (mAutobundledSummaries.containsKey(adjustment.getPackage())) {
+ // Clear summary.
+ final NotificationRecord removed = mNotificationsByKey.get(
+ mAutobundledSummaries.remove(adjustment.getPackage()));
+ if (removed != null) {
+ mNotificationList.remove(removed);
+ cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
+ }
}
}
}
@@ -2203,47 +2205,50 @@
// Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
private void maybeAddAutobundleSummary(Adjustment adjustment) {
- if (adjustment.getSignals() != null
- && adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
- final String newAutoBundleKey =
- adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
- int userId = -1;
- NotificationRecord summaryRecord = null;
- synchronized (mNotificationList) {
- if (!mAutobundledSummaries.containsKey(adjustment.getPackage())
- && newAutoBundleKey != null) {
- // Add summary
- final StatusBarNotification adjustedSbn
- = mNotificationsByKey.get(adjustment.getKey()).sbn;
+ if (adjustment.getSignals() != null) {
+ Bundle.setDefusable(adjustment.getSignals(), true);
+ if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
+ final String newAutoBundleKey =
+ adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
+ int userId = -1;
+ NotificationRecord summaryRecord = null;
+ synchronized (mNotificationList) {
+ if (!mAutobundledSummaries.containsKey(adjustment.getPackage())
+ && newAutoBundleKey != null) {
+ // Add summary
+ final StatusBarNotification adjustedSbn
+ = mNotificationsByKey.get(adjustment.getKey()).sbn;
- final ApplicationInfo appInfo =
- adjustedSbn.getNotification().extras.getParcelable(
- Notification.EXTRA_BUILDER_APPLICATION_INFO);
- final Bundle extras = new Bundle();
- extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
- final Notification summaryNotification =
- new Notification.Builder(getContext()).setSmallIcon(
- adjustedSbn.getNotification().getSmallIcon())
- .setGroupSummary(true)
- .setGroup(newAutoBundleKey)
- .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
- .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
- .build();
- summaryNotification.extras.putAll(extras);
- final StatusBarNotification summarySbn =
- new StatusBarNotification(adjustedSbn.getPackageName(),
- adjustedSbn.getOpPkg(),
- Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
- adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
- summaryNotification, adjustedSbn.getUser(), newAutoBundleKey,
- System.currentTimeMillis());
- summaryRecord = new NotificationRecord(getContext(), summarySbn);
- mAutobundledSummaries.put(adjustment.getPackage(), summarySbn.getKey());
- userId = adjustedSbn.getUser().getIdentifier();
+ final ApplicationInfo appInfo =
+ adjustedSbn.getNotification().extras.getParcelable(
+ Notification.EXTRA_BUILDER_APPLICATION_INFO);
+ final Bundle extras = new Bundle();
+ extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
+ final Notification summaryNotification =
+ new Notification.Builder(getContext()).setSmallIcon(
+ adjustedSbn.getNotification().getSmallIcon())
+ .setGroupSummary(true)
+ .setGroup(newAutoBundleKey)
+ .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
+ .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
+ .build();
+ summaryNotification.extras.putAll(extras);
+ final StatusBarNotification summarySbn =
+ new StatusBarNotification(adjustedSbn.getPackageName(),
+ adjustedSbn.getOpPkg(),
+ Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
+ adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
+ summaryNotification, adjustedSbn.getUser(),
+ newAutoBundleKey,
+ System.currentTimeMillis());
+ summaryRecord = new NotificationRecord(getContext(), summarySbn);
+ mAutobundledSummaries.put(adjustment.getPackage(), summarySbn.getKey());
+ userId = adjustedSbn.getUser().getIdentifier();
+ }
}
- }
- if (summaryRecord != null) {
- mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
+ if (summaryRecord != null) {
+ mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
+ }
}
}
}
@@ -3790,7 +3795,7 @@
return;
}
Set<ComponentName> rankerComponents = queryPackageForServices(
- mRankerServicePackageName, UserHandle.USER_SYSTEM, null);
+ mRankerServicePackageName, UserHandle.USER_SYSTEM);
Iterator<ComponentName> iterator = rankerComponents.iterator();
if (iterator.hasNext()) {
ComponentName rankerComponent = iterator.next();
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 5ee7cc9..43a0b91 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -294,7 +294,7 @@
}
@Override
- public ResolveInfo resolveActivity(Intent intent, UserHandle user)
+ public ActivityInfo resolveActivity(ComponentName component, UserHandle user)
throws RemoteException {
ensureInUserProfiles(user, "Cannot resolve activity for unrelated profile " + user);
if (!isUserEnabled(user)) {
@@ -303,11 +303,11 @@
long ident = Binder.clearCallingIdentity();
try {
- ResolveInfo app = mPm.resolveActivityAsUser(intent,
+ IPackageManager pm = AppGlobals.getPackageManager();
+ return pm.getActivityInfo(component,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
user.getIdentifier());
- return app;
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3b07fe1..1fb260d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4922,6 +4922,7 @@
}
ri = new ResolveInfo(mResolveInfo);
ri.activityInfo = new ActivityInfo(ri.activityInfo);
+ ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction());
ri.activityInfo.applicationInfo = new ApplicationInfo(
ri.activityInfo.applicationInfo);
if (userId != 0) {
@@ -7084,9 +7085,6 @@
pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
}
- UsageStatsManager usageMgr =
- (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE);
-
int curr = 0;
int total = pkgs.size();
for (PackageParser.Package pkg : pkgs) {
@@ -7099,13 +7097,6 @@
continue;
}
- if (!causeFirstBoot && usageMgr.isAppInactive(pkg.packageName)) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Skipping update of of idle app " + pkg.packageName);
- }
- continue;
- }
-
if (DEBUG_DEXOPT) {
Log.i(TAG, "Extracting app " + curr + " of " + total + ": " + pkg.packageName);
}
@@ -16032,28 +16023,36 @@
@Override
public void deleteApplicationCacheFiles(final String packageName,
final IPackageDataObserver observer) {
+ final int userId = UserHandle.getCallingUserId();
+ deleteApplicationCacheFilesAsUser(packageName, userId, observer);
+ }
+
+ @Override
+ public void deleteApplicationCacheFilesAsUser(final String packageName, final int userId,
+ final IPackageDataObserver observer) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_CACHE_FILES, null);
- // Queue up an async operation since the package deletion may take a little while.
- final int userId = UserHandle.getCallingUserId();
+ enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ /* requireFullPermission= */ true, /* checkShell= */ false,
+ "delete application cache files");
final PackageParser.Package pkg;
synchronized (mPackages) {
pkg = mPackages.get(packageName);
}
+ // Queue up an async operation since the package deletion may take a little while.
mHandler.post(new Runnable() {
public void run() {
- try (PackageFreezer freezer = freezePackage(packageName,
- "deleteApplicationCacheFiles")) {
- synchronized (mInstallLock) {
- final int flags = StorageManager.FLAG_STORAGE_DE
- | StorageManager.FLAG_STORAGE_CE;
- clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY);
- clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- }
- clearExternalStorageDataSync(packageName, userId, false);
+ synchronized (mInstallLock) {
+ final int flags = StorageManager.FLAG_STORAGE_DE
+ | StorageManager.FLAG_STORAGE_CE;
+ // We're only clearing cache files, so we don't care if the
+ // app is unfrozen and still able to run
+ clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY);
+ clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
+ clearExternalStorageDataSync(packageName, userId, false);
if (observer != null) {
try {
observer.onRemoveCompleted(packageName, true);
@@ -16098,11 +16097,17 @@
mInstaller.getAppSize(ps.volumeUuid, packageName, userId,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE,
ps.getCeDataInode(userId), ps.codePathString, stats);
- return true;
} catch (InstallerException e) {
Slog.w(TAG, String.valueOf(e));
return false;
}
+
+ // For now, ignore code size of packages on system partition
+ if (isSystemApp(ps) && !isUpdatedSystemApp(ps)) {
+ stats.codeSize = 0;
+ }
+
+ return true;
}
private int getUidTargetSdkVersionLockedLPr(int uid) {
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index aa10c08..a6350fe 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -92,7 +92,7 @@
* MAC_PERMISSIONS class variable which is set at class load time which itself
* is based on the USE_OVERRIDE_POLICY class variable. For further guidance on
* the proper structure of a mac_permissions.xml file consult the source code
- * located at external/sepolicy/mac_permissions.xml.
+ * located at system/sepolicy/mac_permissions.xml.
*
* @return boolean indicating if policy was correctly loaded. A value of false
* typically indicates a structural problem with the xml or incorrectly
@@ -373,7 +373,7 @@
* {@link Policy#getMatchedSeinfo} method. To create an instance of this use the
* {@link PolicyBuilder} pattern class, where each instance is validated against a set
* of invariants before being built and returned. Each instance can be guaranteed to
- * hold one valid policy stanza as outlined in the external/sepolicy/mac_permissions.xml
+ * hold one valid policy stanza as outlined in the system/sepolicy/mac_permissions.xml
* file.
* <p>
* The following is an example of how to use {@link Policy.PolicyBuilder} to create a
@@ -519,7 +519,7 @@
* A nested builder class to create {@link Policy} instances. A {@link Policy}
* class instance represents one valid policy stanza found in a mac_permissions.xml
* file. A valid policy stanza is defined to be a signer stanza which obeys the rules
- * outlined in external/sepolicy/mac_permissions.xml. The {@link #build} method
+ * outlined in system/sepolicy/mac_permissions.xml. The {@link #build} method
* ensures a set of invariants are upheld enforcing the correct stanza structure
* before returning a valid Policy object.
*/
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 847f993..7debf9b 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2686,7 +2686,7 @@
void writePermissionLPr(XmlSerializer serializer, BasePermission bp)
throws XmlPullParserException, java.io.IOException {
- if (bp.type != BasePermission.TYPE_BUILTIN && bp.sourcePackage != null) {
+ if (bp.sourcePackage != null) {
serializer.startTag(null, TAG_ITEM);
serializer.attribute(null, ATTR_NAME, bp.name);
serializer.attribute(null, "package", bp.sourcePackage);
@@ -3348,8 +3348,12 @@
final String ptype = parser.getAttributeValue(null, "type");
if (name != null && sourcePackage != null) {
final boolean dynamic = "dynamic".equals(ptype);
- final BasePermission bp = new BasePermission(name.intern(), sourcePackage,
- dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL);
+ BasePermission bp = out.get(name);
+ // If the permission is builtin, do not clobber it.
+ if (bp == null || bp.type != BasePermission.TYPE_BUILTIN) {
+ bp = new BasePermission(name.intern(), sourcePackage,
+ dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL);
+ }
bp.protectionLevel = readInt(parser, null, "protection",
PermissionInfo.PROTECTION_NORMAL);
bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 58559a5..b9b65eb 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -28,6 +28,7 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -37,7 +38,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
@@ -51,6 +52,7 @@
private static final String TAG_INTENT_EXTRAS = "intent-extras";
private static final String TAG_EXTRAS = "extras";
private static final String TAG_SHORTCUT = "shortcut";
+ private static final String TAG_CATEGORIES = "categories";
private static final String ATTR_NAME = "name";
private static final String ATTR_DYNAMIC_COUNT = "dynamic-count";
@@ -67,6 +69,11 @@
private static final String ATTR_ICON_RES = "icon-res";
private static final String ATTR_BITMAP_PATH = "bitmap-path";
+ private static final String NAME_CATEGORIES = "categories";
+
+ private static final String TAG_STRING_ARRAY_XMLUTILS = "string-array";
+ private static final String ATTR_NAME_XMLUTILS = "name";
+
/**
* All the shortcuts from the package, keyed on IDs.
*/
@@ -305,7 +312,7 @@
* and return true. Otherwise just return false.
*/
public boolean tryApiCall(@NonNull ShortcutService s) {
- if (getApiCallCount(s) >= s.mMaxDailyUpdates) {
+ if (getApiCallCount(s) >= s.mMaxUpdatesPerInterval) {
return false;
}
mApiCallCount++;
@@ -485,6 +492,16 @@
ShortcutService.writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath());
}
+ {
+ final List<String> cat = si.getCategories();
+ if (cat != null && cat.size() > 0) {
+ out.startTag(null, TAG_CATEGORIES);
+ XmlUtils.writeStringArrayXml(cat.toArray(new String[cat.size()]),
+ NAME_CATEGORIES, out);
+ out.endTag(null, TAG_CATEGORIES);
+ }
+ }
+
ShortcutService.writeTagExtra(out, TAG_INTENT_EXTRAS,
si.getIntentPersistableExtras());
ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
@@ -550,6 +567,7 @@
int flags;
int iconRes;
String bitmapPath;
+ String[] categories = null;
id = ShortcutService.parseStringAttribute(parser, ATTR_ID);
activityComponent = ShortcutService.parseComponentNameAttribute(parser,
@@ -583,11 +601,21 @@
case TAG_EXTRAS:
extras = PersistableBundle.restoreFromXml(parser);
continue;
+ case TAG_CATEGORIES:
+ // This just contains string-array.
+ continue;
+ case TAG_STRING_ARRAY_XMLUTILS:
+ if (NAME_CATEGORIES.equals(ShortcutService.parseStringAttribute(parser,
+ ATTR_NAME_XMLUTILS))) {
+ categories = XmlUtils.readThisStringArrayXml(parser, TAG_STRING_ARRAY_XMLUTILS, null);
+ }
+ continue;
}
throw ShortcutService.throwForInvalidTag(depth, tag);
}
return new ShortcutInfo(
- userId, id, packageName, activityComponent, /* icon =*/ null, title, text, intent,
+ userId, id, packageName, activityComponent, /* icon =*/ null, title, text,
+ (categories == null ? null : Arrays.asList(categories)), intent,
intentPersistableExtras, weight, extras, lastChangedTimestamp, flags,
iconRes, bitmapPath);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1641e1d..ac6510a 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -126,10 +126,10 @@
static final boolean DEBUG_LOAD = false; // STOPSHIP if true
@VisibleForTesting
- static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day
+ static final long DEFAULT_RESET_INTERVAL_SEC = 60 * 60; // 1 hour
@VisibleForTesting
- static final int DEFAULT_MAX_DAILY_UPDATES = 10;
+ static final int DEFAULT_MAX_UPDATES_PER_INTERVAL = 2;
@VisibleForTesting
static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 5;
@@ -180,7 +180,7 @@
/**
* Key name for the max number of modifying API calls per app for every interval. (int)
*/
- String KEY_MAX_DAILY_UPDATES = "max_daily_updates";
+ String KEY_MAX_UPDATES_PER_INTERVAL = "max_updates_per_interval";
/**
* Key name for the max icon dimensions in DP, for non-low-memory devices.
@@ -232,9 +232,9 @@
private int mMaxDynamicShortcuts;
/**
- * Max number of updating API calls that each application can make a day.
+ * Max number of updating API calls that each application can make during the interval.
*/
- int mMaxDailyUpdates;
+ int mMaxUpdatesPerInterval;
/**
* Actual throttling-reset interval. By default it's a day.
@@ -426,8 +426,8 @@
ConfigConstants.KEY_RESET_INTERVAL_SEC, DEFAULT_RESET_INTERVAL_SEC)
* 1000L);
- mMaxDailyUpdates = Math.max(0, (int) parser.getLong(
- ConfigConstants.KEY_MAX_DAILY_UPDATES, DEFAULT_MAX_DAILY_UPDATES));
+ mMaxUpdatesPerInterval = Math.max(0, (int) parser.getLong(
+ ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL, DEFAULT_MAX_UPDATES_PER_INTERVAL));
mMaxDynamicShortcuts = Math.max(0, (int) parser.getLong(
ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP));
@@ -1319,10 +1319,13 @@
}
@Override
- public boolean addDynamicShortcut(String packageName, ShortcutInfo newShortcut,
+ public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
+ final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+ final int size = newShortcuts.size();
+
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
@@ -1330,12 +1333,15 @@
if (!ps.tryApiCall(this)) {
return false;
}
+ for (int i = 0; i < size; i++) {
+ final ShortcutInfo newShortcut = newShortcuts.get(i);
- // Validate the shortcut.
- fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
+ // Validate the shortcut.
+ fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
- // Add it.
- ps.addDynamicShortcut(this, newShortcut);
+ // Add it.
+ ps.addDynamicShortcut(this, newShortcut);
+ }
}
userPackageChanged(packageName, userId);
@@ -1343,19 +1349,22 @@
}
@Override
- public void deleteDynamicShortcut(String packageName, String shortcutId,
+ public void removeDynamicShortcuts(String packageName, List shortcutIds,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
- Preconditions.checkStringNotEmpty(shortcutId, "shortcutId must be provided");
+ Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
synchronized (mLock) {
- getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(this, shortcutId);
+ for (int i = shortcutIds.size() - 1; i >= 0; i--) {
+ getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(this,
+ Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)));
+ }
}
userPackageChanged(packageName, userId);
}
@Override
- public void deleteAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
+ public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
verifyCaller(packageName, userId);
synchronized (mLock) {
@@ -1409,7 +1418,7 @@
verifyCaller(packageName, userId);
synchronized (mLock) {
- return mMaxDailyUpdates
+ return mMaxUpdatesPerInterval
- getPackageShortcutsLocked(packageName, userId).getApiCallCount(this);
}
}
@@ -2079,8 +2088,8 @@
pw.println(mSaveDelayMillis);
pw.print(" resetInterval:");
pw.println(mResetInterval);
- pw.print(" maxDailyUpdates:");
- pw.println(mMaxDailyUpdates);
+ pw.print(" maxUpdatesPerInterval:");
+ pw.println(mMaxUpdatesPerInterval);
pw.print(" maxDynamicShortcuts:");
pw.println(mMaxDynamicShortcuts);
pw.println();
@@ -2423,8 +2432,8 @@
}
@VisibleForTesting
- int getMaxDailyUpdatesForTest() {
- return mMaxDailyUpdates;
+ int getMaxUpdatesPerIntervalForTest() {
+ return mMaxUpdatesPerInterval;
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index 27077f2..553c5de 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -80,8 +80,6 @@
.getInteger(R.integer.config_immersive_mode_confirmation_panic);
mWindowManager = (WindowManager)
mContext.getSystemService(Context.WINDOW_SERVICE);
- mVrManager = (IVrManager) IVrManager.Stub.asInterface(
- ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE));
}
private long getNavBarExitDuration() {
@@ -121,11 +119,18 @@
private boolean getVrMode() {
boolean vrMode = false;
- try {
- vrMode = mVrManager.getVrModeState();
- } catch (RemoteException ex) { }
+ if (mVrManager == null) {
+ // lazily grab this service since it may not be available at construction time
+ mVrManager = (IVrManager) IVrManager.Stub.asInterface(
+ ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE));
+ }
+ if (mVrManager != null) {
+ try {
+ vrMode = mVrManager.getVrModeState();
+ } catch (RemoteException ex) { }
+ }
return vrMode;
- }
+ }
public void immersiveModeChanged(String pkg, boolean isImmersiveMode,
boolean userSetupComplete) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5ce451f..d8c0775 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -318,6 +318,7 @@
AccessibilityManager mAccessibilityManager;
BurnInProtectionHelper mBurnInProtectionHelper;
AppOpsManager mAppOpsManager;
+ private boolean mHasFeatureWatch;
// Vibrator pattern for haptic feedback of a long press.
long[] mLongPressVibePattern;
@@ -693,6 +694,7 @@
= new LogDecelerateInterpolator(100, 0);
private final MutableBoolean mTmpBoolean = new MutableBoolean(false);
+
private static final int MSG_ENABLE_POINTER_LOCATION = 1;
private static final int MSG_DISABLE_POINTER_LOCATION = 2;
private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
@@ -1501,6 +1503,7 @@
mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
// Init display burn-in protection
boolean burnInProtectionEnabled = context.getResources().getBoolean(
@@ -5780,9 +5783,14 @@
}
private boolean shouldDispatchInputWhenNonInteractive() {
- // Send events to keyguard while the screen is on.
- if (isKeyguardShowingAndNotOccluded() && mDisplay != null
- && mDisplay.getState() != Display.STATE_OFF) {
+ final boolean displayOff = (mDisplay == null || mDisplay.getState() == Display.STATE_OFF);
+
+ if (displayOff && !mHasFeatureWatch) {
+ return false;
+ }
+
+ // Send events to keyguard while the screen is on and it's showing.
+ if (isKeyguardShowingAndNotOccluded() && !displayOff) {
return true;
}
@@ -6695,7 +6703,7 @@
@Override public void run() {
if (mBootMsgDialog == null) {
int theme;
- if (mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH)) {
+ if (mHasFeatureWatch) {
theme = com.android.internal.R.style.Theme_Micro_Dialog_Alert;
} else if (mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION)) {
theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 984fb76..3c84fc2 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -974,7 +974,6 @@
public void register(Context context) {
IntentFilter filter = new IntentFilter();
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
context.registerReceiverAsUser(this,
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 07e017f..49ff385 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -105,6 +105,7 @@
new RemoteCallbackList<>();
private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>();
private String mPreviousNotificationPolicyAccessPackage;
+ private String mPreviousCoarseLocationPackage;
private String mPreviousManageOverlayPackage;
private static final int MSG_VR_STATE_CHANGE = 0;
@@ -446,6 +447,7 @@
mWasDefaultGranted = true;
+ grantCoarseLocationAccess(pName, userId);
grantOverlayAccess(pName, userId);
grantNotificationPolicyAccess(pName);
grantNotificationListenerAccess(pName, userId);
@@ -475,6 +477,7 @@
String pName = component.getPackageName();
if (mWasDefaultGranted) {
+ revokeCoarseLocationAccess(userId);
revokeOverlayAccess(userId);
revokeNotificationPolicyAccess(pName);
revokeNotificiationListenerAccess();
@@ -483,6 +486,27 @@
}
+ private void grantCoarseLocationAccess(String pkg, UserHandle userId) {
+ PackageManager pm = mContext.getPackageManager();
+ boolean prev = (PackageManager.PERMISSION_GRANTED ==
+ pm.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, pkg));
+ mPreviousCoarseLocationPackage = null;
+ if (!prev) {
+ pm.grantRuntimePermission(pkg, android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ userId);
+ mPreviousCoarseLocationPackage = pkg;
+ }
+ }
+
+ private void revokeCoarseLocationAccess(UserHandle userId) {
+ PackageManager pm = mContext.getPackageManager();
+ if (mPreviousCoarseLocationPackage != null) {
+ pm.revokeRuntimePermission(mPreviousCoarseLocationPackage,
+ android.Manifest.permission.ACCESS_COARSE_LOCATION, userId);
+ mPreviousCoarseLocationPackage = null;
+ }
+ }
+
private void grantOverlayAccess(String pkg, UserHandle userId) {
PackageManager pm = mContext.getPackageManager();
boolean prev = (PackageManager.PERMISSION_GRANTED ==
@@ -504,7 +528,6 @@
}
}
-
private void grantNotificationPolicyAccess(String pkg) {
NotificationManager nm = mContext.getSystemService(NotificationManager.class);
boolean prev = nm.isNotificationPolicyAccessGrantedForPackage(pkg);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index fe32104..10e30ed 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -16,9 +16,12 @@
package com.android.server.wallpaper;
-import static android.app.WallpaperManager.FLAG_SYSTEM;
import static android.app.WallpaperManager.FLAG_LOCK;
-import static android.os.ParcelFileDescriptor.*;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -41,27 +44,26 @@
import android.content.ServiceConnection;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
-import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
+import android.os.FileObserver;
import android.os.FileUtils;
import android.os.IBinder;
import android.os.IRemoteCallback;
-import android.os.RemoteException;
-import android.os.FileObserver;
import android.os.ParcelFileDescriptor;
import android.os.RemoteCallbackList;
+import android.os.RemoteException;
import android.os.SELinux;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -79,35 +81,64 @@
import android.view.IWindowManager;
import android.view.WindowManager;
-import java.io.BufferedOutputStream;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.List;
+import com.android.internal.R;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
+import com.android.server.EventLogTags;
+import com.android.server.SystemService;
+
+import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.JournaledFile;
-import com.android.internal.R;
-import com.android.server.EventLogTags;
-
-import libcore.io.IoUtils;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
public class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperManagerService";
static final boolean DEBUG = false;
+ public static class Lifecycle extends SystemService {
+ private WallpaperManagerService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mService = new WallpaperManagerService(getContext());
+ publishBinderService(Context.WALLPAPER_SERVICE, mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mService.systemReady();
+ } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ mService.switchUser(UserHandle.USER_SYSTEM, null);
+ }
+ }
+
+ @Override
+ public void onUnlockUser(int userHandle) {
+ mService.onUnlockUser(userHandle);
+ }
+ }
+
final Object mLock = new Object();
/**
@@ -417,6 +448,7 @@
final AppOpsManager mAppOpsManager;
WallpaperData mLastWallpaper;
IWallpaperManagerCallback mKeyguardListener;
+ boolean mWaitingForUnlock;
/**
* ID of the current wallpaper, changed every time anything sets a wallpaper.
@@ -744,8 +776,9 @@
if (wallpaper.wallpaperComponent != null
&& isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
try {
- mContext.getPackageManager().getServiceInfo(
- wallpaper.wallpaperComponent, 0);
+ mContext.getPackageManager().getServiceInfo(wallpaper.wallpaperComponent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
} catch (NameNotFoundException e) {
Slog.w(TAG, "Wallpaper component gone, removing: "
+ wallpaper.wallpaperComponent);
@@ -755,8 +788,9 @@
if (wallpaper.nextWallpaperComponent != null
&& isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
try {
- mContext.getPackageManager().getServiceInfo(
- wallpaper.nextWallpaperComponent, 0);
+ mContext.getPackageManager().getServiceInfo(wallpaper.nextWallpaperComponent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
} catch (NameNotFoundException e) {
wallpaper.nextWallpaperComponent = null;
}
@@ -793,7 +827,7 @@
}
}
- public void systemRunning() {
+ void systemReady() {
if (DEBUG) Slog.v(TAG, "systemReady");
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
// If we think we're going to be using the system image wallpaper imagery, make
@@ -818,9 +852,6 @@
Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring");
}
}
- switchWallpaper(wallpaper, null);
- wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
- wallpaper.wallpaperObserver.startWatching();
IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_REMOVED);
@@ -828,7 +859,7 @@
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
+ final String action = intent.getAction();
if (Intent.ACTION_USER_REMOVED.equals(action)) {
onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL));
@@ -892,6 +923,14 @@
mLockWallpaperMap.remove(userId);
}
+ void onUnlockUser(int userId) {
+ synchronized (mLock) {
+ if (mCurrentUserId == userId && mWaitingForUnlock) {
+ switchUser(userId, null);
+ }
+ }
+ }
+
void onRemoveUser(int userId) {
if (userId < 1) return;
@@ -919,18 +958,34 @@
void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
synchronized (mLock) {
- RuntimeException e = null;
- try {
- ComponentName cname = wallpaper.wallpaperComponent != null ?
- wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
- if (bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
- return;
+ mWaitingForUnlock = false;
+ final ComponentName cname = wallpaper.wallpaperComponent != null ?
+ wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
+ if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
+ // We failed to bind the desired wallpaper, but that might
+ // happen if the wallpaper isn't direct-boot aware
+ ServiceInfo si = null;
+ try {
+ si = mIPackageManager.getServiceInfo(cname,
+ PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId);
+ } catch (RemoteException ignored) {
}
- } catch (RuntimeException e1) {
- e = e1;
+
+ if (si == null) {
+ Slog.w(TAG, "Failure starting previous wallpaper; clearing");
+ clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
+ } else {
+ Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
+ // We might end up persisting the current wallpaper data
+ // while locked, so pretend like the component was actually
+ // bound into place
+ wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
+ final WallpaperData fallback = new WallpaperData(wallpaper.userId,
+ WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
+ mWaitingForUnlock = true;
+ }
}
- Slog.w(TAG, "Failure starting previous wallpaper", e);
- clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
}
}
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index a5d68da..876bb20 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -68,6 +68,7 @@
public WebViewProviderInfo[] getWebViewPackages() {
int numFallbackPackages = 0;
int numAvailableByDefaultPackages = 0;
+ int numAvByDefaultAndNotFallback = 0;
XmlResourceParser parser = null;
List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
try {
@@ -111,6 +112,9 @@
}
if (currentProvider.availableByDefault) {
numAvailableByDefaultPackages++;
+ if (!currentProvider.isFallback) {
+ numAvByDefaultAndNotFallback++;
+ }
}
webViewProviders.add(currentProvider);
}
@@ -127,6 +131,10 @@
throw new AndroidRuntimeException("There must be at least one WebView package "
+ "that is available by default");
}
+ if (numAvByDefaultAndNotFallback == 0) {
+ throw new AndroidRuntimeException("There must be at least one WebView package "
+ + "that is available by default and not a fallback");
+ }
return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index df5d027..8c01c4c 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -245,8 +245,16 @@
synchronized(mLock) {
try {
newPackage = findPreferredWebViewPackage();
- if (mCurrentWebViewPackage != null)
+ if (mCurrentWebViewPackage != null) {
oldProviderName = mCurrentWebViewPackage.packageName;
+ if (changedState == WebViewUpdateService.PACKAGE_CHANGED
+ && newPackage.packageName.equals(oldProviderName)) {
+ // If we don't change package name we should only rerun the
+ // preparation phase if the current package has been replaced
+ // (not if it has been enabled/disabled).
+ return;
+ }
+ }
// Only trigger update actions if the updated package is the one
// that will be used, or the one that was in use before the
// update, or if we haven't seen a valid WebView package before.
@@ -283,6 +291,13 @@
try {
synchronized(mLock) {
mCurrentWebViewPackage = findPreferredWebViewPackage();
+ // Don't persist the user-chosen setting across boots if the package being
+ // chosen is not used (could be disabled or uninstalled) so that the user won't
+ // be surprised by the device switching to using a certain webview package,
+ // that was uninstalled/disabled a long time ago, if it is installed/enabled
+ // again.
+ mSystemInterface.updateUserSetting(mContext,
+ mCurrentWebViewPackage.packageName);
onWebViewProviderChanged(mCurrentWebViewPackage);
}
} catch (Throwable t) {
@@ -337,7 +352,6 @@
mAnyWebViewInstalled = true;
if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
mCurrentWebViewPackage = newPackage;
- mSystemInterface.updateUserSetting(mContext, newPackage.packageName);
// The relro creations might 'finish' (not start at all) before
// WebViewFactory.onWebViewProviderChanged which means we might not know the
@@ -424,9 +438,12 @@
}
}
- // Could not find any enabled package either, use the most stable provider.
+ // Could not find any enabled package either, use the most stable and default-available
+ // provider.
for (ProviderAndPackageInfo providerAndPackage : providers) {
- return providerAndPackage.packageInfo;
+ if (providerAndPackage.provider.availableByDefault) {
+ return providerAndPackage.packageInfo;
+ }
}
mAnyWebViewInstalled = false;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 28379f4..1f16481 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -290,7 +290,7 @@
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
TaskStack stack = mStacks.get(stackNdx);
stack.getBounds(mTmpRect);
- if (!mTmpRect.contains(x, y)) {
+ if (!mTmpRect.contains(x, y) || stack.isAdjustedForMinimizedDockedStack()) {
continue;
}
final ArrayList<Task> tasks = stack.getTasks();
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 6ac71c7..ff537be 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -270,6 +270,19 @@
mDockedStackListeners.finishBroadcast();
}
+ void notifyDockSideChanged(int newDockSide) {
+ final int size = mDockedStackListeners.beginBroadcast();
+ for (int i = 0; i < size; ++i) {
+ final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+ try {
+ listener.onDockSideChanged(newDockSide);
+ } catch (RemoteException e) {
+ Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
+ }
+ }
+ mDockedStackListeners.finishBroadcast();
+ }
+
void registerDockedStackListener(IDockedStackListener listener) {
mDockedStackListeners.register(listener);
notifyDockedDividerVisibilityChanged(wasVisible());
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index eea0e73..be9fb26 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -294,7 +294,8 @@
final WindowState child = windows.get(winNdx);
final InputChannel inputChannel = child.mInputChannel;
final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
- if (inputChannel == null || inputWindowHandle == null || child.mRemoved) {
+ if (inputChannel == null || inputWindowHandle == null || child.mRemoved
+ || child.isAdjustedForMinimizedDock()) {
// Skip this window because it cannot possibly receive input.
continue;
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 446b74b..7074a83 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -16,6 +16,20 @@
package com.android.server.wm;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
+
import android.app.ActivityManager.StackId;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -35,20 +49,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
-import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
public class TaskStack implements DimLayer.DimLayerUser,
BoundsAnimationController.AnimateBoundsUser {
@@ -379,10 +379,15 @@
return false;
}
+ final int oldDockSide = mStackId == DOCKED_STACK_ID ? getDockSide() : DOCKED_INVALID;
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
if (mStackId == DOCKED_STACK_ID) {
repositionDockedStackAfterRotation(mTmpRect2);
snapDockedStackAfterRotation(mTmpRect2);
+ final int newDockSide = getDockSide(mTmpRect2);
+ if (oldDockSide != newDockSide) {
+ mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
+ }
}
if (scheduleResize) {
@@ -910,7 +915,7 @@
// Calculate the content bounds excluding the area occupied by IME
getDisplayContent().getContentRect(displayContentRect);
contentBounds.set(displayContentRect);
- int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
+ int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
// if IME window is animating, get its actual vertical shown position (but no smaller than
// the final target vertical position)
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 57f38d1..57dc97a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -18,6 +18,7 @@
import android.Manifest;
import android.animation.ValueAnimator;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
@@ -153,6 +154,8 @@
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.Socket;
import java.text.DateFormat;
import java.util.ArrayList;
@@ -332,6 +335,14 @@
private static final String PROPERTY_BUILD_DATE_UTC = "ro.build.date.utc";
+ // Enums for animation scale update types.
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({WINDOW_ANIMATION_SCALE, TRANSITION_ANIMATION_SCALE, ANIMATION_DURATION_SCALE})
+ private @interface UpdateAnimationScaleMode {};
+ private static final int WINDOW_ANIMATION_SCALE = 0;
+ private static final int TRANSITION_ANIMATION_SCALE = 1;
+ private static final int ANIMATION_DURATION_SCALE = 2;
+
final private KeyguardDisableHandler mKeyguardDisableHandler;
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -613,18 +624,42 @@
private final class SettingsObserver extends ContentObserver {
private final Uri mDisplayInversionEnabledUri =
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+ private final Uri mWindowAnimationScaleUri =
+ Settings.Global.getUriFor(Settings.Global.WINDOW_ANIMATION_SCALE);
+ private final Uri mTransitionAnimationScaleUri =
+ Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE);
+ private final Uri mAnimationDurationScaleUri =
+ Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE);
public SettingsObserver() {
super(new Handler());
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(mWindowAnimationScaleUri, false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(mTransitionAnimationScaleUri, false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(mAnimationDurationScaleUri, false, this,
+ UserHandle.USER_ALL);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
if (mDisplayInversionEnabledUri.equals(uri)) {
updateCircularDisplayMaskIfNeeded();
+ } else {
+ @UpdateAnimationScaleMode
+ final int mode;
+ if (uri.equals(mWindowAnimationScaleUri)) {
+ mode = WINDOW_ANIMATION_SCALE;
+ } else if (uri.equals(mTransitionAnimationScaleUri)) {
+ mode = TRANSITION_ANIMATION_SCALE;
+ } else { // uri.equals(mAnimationDurationScaleUri)
+ mode = ANIMATION_DURATION_SCALE;
+ }
+ Message m = mH.obtainMessage(H.UPDATE_ANIMATION_SCALE, mode, 0);
+ mH.sendMessage(m);
}
}
}
@@ -2072,6 +2107,11 @@
if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
reportNewConfig = true;
}
+ if (attrs.removeTimeoutMilliseconds > 0) {
+ mH.sendMessageDelayed(
+ mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win),
+ attrs.removeTimeoutMilliseconds);
+ }
}
if (reportNewConfig) {
@@ -3905,16 +3945,6 @@
return;
}
- if (transferStartingWindow(transferFrom, wtoken)) {
- return;
- }
-
- // There is no existing starting window, and the caller doesn't
- // want us to create one, so that's it!
- if (!createIfNeeded) {
- return;
- }
-
// If this is a translucent window, then don't
// show a starting window -- the current effect (a full-screen
// opaque starting window that fades away to the real contents
@@ -3960,6 +3990,16 @@
}
}
+ if (transferStartingWindow(transferFrom, wtoken)) {
+ return;
+ }
+
+ // There is no existing starting window, and the caller doesn't
+ // want us to create one, so that's it!
+ if (!createIfNeeded) {
+ return;
+ }
+
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
labelRes, icon, logo, windowFlags);
@@ -5986,7 +6026,13 @@
"screenshotApplications()")) {
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
- return screenshotApplicationsInner(appToken, displayId, width, height, false, frameScale);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
+ return screenshotApplicationsInner(appToken, displayId, width, height, false,
+ frameScale);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
}
Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width, int height,
@@ -7747,6 +7793,8 @@
public static final int NOTIFY_APP_TRANSITION_CANCELLED = 48;
public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
+ public static final int UPDATE_ANIMATION_SCALE = 51;
+ public static final int WINDOW_REMOVE_TIMEOUT = 52;
/**
* Used to denote that an integer field in a message will not be used.
@@ -8030,6 +8078,36 @@
break;
}
+ case UPDATE_ANIMATION_SCALE: {
+ @UpdateAnimationScaleMode
+ final int mode = msg.arg1;
+ switch (mode) {
+ case WINDOW_ANIMATION_SCALE: {
+ mWindowAnimationScaleSetting = Settings.Global.getFloat(
+ mContext.getContentResolver(),
+ Settings.Global.WINDOW_ANIMATION_SCALE,
+ mWindowAnimationScaleSetting);
+ break;
+ }
+ case TRANSITION_ANIMATION_SCALE: {
+ mTransitionAnimationScaleSetting = Settings.Global.getFloat(
+ mContext.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE,
+ mTransitionAnimationScaleSetting);
+ break;
+ }
+ case ANIMATION_DURATION_SCALE: {
+ mAnimatorDurationScaleSetting = Settings.Global.getFloat(
+ mContext.getContentResolver(),
+ Settings.Global.ANIMATOR_DURATION_SCALE,
+ mAnimatorDurationScaleSetting);
+ dispatchNewAnimatorScaleLocked(null);
+ break;
+ }
+ }
+ break;
+ }
+
case FORCE_GC: {
synchronized (mWindowMap) {
// Since we're holding both mWindowMap and mAnimator we don't need to
@@ -8329,6 +8407,18 @@
mAmInternal.notifyStartingWindowDrawn();
}
break;
+ case WINDOW_REMOVE_TIMEOUT: {
+ final WindowState window = (WindowState) msg.obj;
+ synchronized(mWindowMap) {
+ // It's counterintuitive that we check that "mWindowRemovalAllowed"
+ // is false. But in fact if it's true, it means a remove has already
+ // been requested and we better just not do anything.
+ if (!window.mRemoved && !window.mWindowRemovalAllowed) {
+ removeWindowLocked(window);
+ }
+ }
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: exit");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c991130..8371cfe 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -774,10 +774,6 @@
applyGravityAndUpdateFrame(layoutContainingFrame, layoutDisplayFrame);
- // Offset the actual frame by the amount layout frame is off.
- mFrame.offset(-layoutXDiff, -layoutYDiff);
- mCompatFrame.offset(-layoutXDiff, -layoutYDiff);
-
// Calculate the outsets before the content frame gets shrinked to the window frame.
if (hasOutsets) {
mOutsets.set(Math.max(mContentFrame.left - mOutsetFrame.left, 0),
@@ -816,20 +812,20 @@
mMovedByResize = true;
}
} else {
- mContentFrame.set(Math.max(mContentFrame.left, layoutContainingFrame.left),
- Math.max(mContentFrame.top, layoutContainingFrame.top),
- Math.min(mContentFrame.right, layoutContainingFrame.right),
- Math.min(mContentFrame.bottom, layoutContainingFrame.bottom));
+ mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
+ Math.max(mContentFrame.top, mFrame.top),
+ Math.min(mContentFrame.right, mFrame.right),
+ Math.min(mContentFrame.bottom, mFrame.bottom));
- mVisibleFrame.set(Math.max(mVisibleFrame.left, layoutContainingFrame.left),
- Math.max(mVisibleFrame.top, layoutContainingFrame.top),
- Math.min(mVisibleFrame.right, layoutContainingFrame.right),
- Math.min(mVisibleFrame.bottom, layoutContainingFrame.bottom));
+ mVisibleFrame.set(Math.max(mVisibleFrame.left, mFrame.left),
+ Math.max(mVisibleFrame.top, mFrame.top),
+ Math.min(mVisibleFrame.right, mFrame.right),
+ Math.min(mVisibleFrame.bottom, mFrame.bottom));
- mStableFrame.set(Math.max(mStableFrame.left, layoutContainingFrame.left),
- Math.max(mStableFrame.top, layoutContainingFrame.top),
- Math.min(mStableFrame.right, layoutContainingFrame.right),
- Math.min(mStableFrame.bottom, layoutContainingFrame.bottom));
+ mStableFrame.set(Math.max(mStableFrame.left, mFrame.left),
+ Math.max(mStableFrame.top, mFrame.top),
+ Math.min(mStableFrame.right, mFrame.right),
+ Math.min(mStableFrame.bottom, mFrame.bottom));
}
if (fullscreenTask && !windowsAreFloating) {
@@ -857,30 +853,33 @@
getDisplayContent().getLogicalDisplayRect(mTmpRect);
// Override right and/or bottom insets in case if the frame doesn't fit the screen in
// non-fullscreen mode.
- boolean overrideRightInset = !fullscreenTask && layoutContainingFrame.right > mTmpRect.right;
- boolean overrideBottomInset = !fullscreenTask && layoutContainingFrame.bottom > mTmpRect.bottom;
- mContentInsets.set(mContentFrame.left - layoutContainingFrame.left,
- mContentFrame.top - layoutContainingFrame.top,
+ boolean overrideRightInset = !fullscreenTask && mFrame.right > mTmpRect.right;
+ boolean overrideBottomInset = !fullscreenTask && mFrame.bottom > mTmpRect.bottom;
+ mContentInsets.set(mContentFrame.left - mFrame.left,
+ mContentFrame.top - mFrame.top,
overrideRightInset ? mTmpRect.right - mContentFrame.right
- : layoutContainingFrame.right - mContentFrame.right,
+ : mFrame.right - mContentFrame.right,
overrideBottomInset ? mTmpRect.bottom - mContentFrame.bottom
- : layoutContainingFrame.bottom - mContentFrame.bottom);
+ : mFrame.bottom - mContentFrame.bottom);
- mVisibleInsets.set(mVisibleFrame.left - layoutContainingFrame.left,
- mVisibleFrame.top - layoutContainingFrame.top,
+ mVisibleInsets.set(mVisibleFrame.left - mFrame.left,
+ mVisibleFrame.top - mFrame.top,
overrideRightInset ? mTmpRect.right - mVisibleFrame.right
- : layoutContainingFrame.right - mVisibleFrame.right,
+ : mFrame.right - mVisibleFrame.right,
overrideBottomInset ? mTmpRect.bottom - mVisibleFrame.bottom
- : layoutContainingFrame.bottom - mVisibleFrame.bottom);
+ : mFrame.bottom - mVisibleFrame.bottom);
- mStableInsets.set(Math.max(mStableFrame.left - layoutContainingFrame.left, 0),
- Math.max(mStableFrame.top - layoutContainingFrame.top, 0),
+ mStableInsets.set(Math.max(mStableFrame.left - mFrame.left, 0),
+ Math.max(mStableFrame.top - mFrame.top, 0),
overrideRightInset ? Math.max(mTmpRect.right - mStableFrame.right, 0)
- : Math.max(layoutContainingFrame.right - mStableFrame.right, 0),
+ : Math.max(mFrame.right - mStableFrame.right, 0),
overrideBottomInset ? Math.max(mTmpRect.bottom - mStableFrame.bottom, 0)
- : Math.max(layoutContainingFrame.bottom - mStableFrame.bottom, 0));
+ : Math.max(mFrame.bottom - mStableFrame.bottom, 0));
}
+ // Offset the actual frame by the amount layout frame is off.
+ mFrame.offset(-layoutXDiff, -layoutYDiff);
+ mCompatFrame.offset(-layoutXDiff, -layoutYDiff);
mContentFrame.offset(-layoutXDiff, -layoutYDiff);
mVisibleFrame.offset(-layoutXDiff, -layoutYDiff);
mStableFrame.offset(-layoutXDiff, -layoutYDiff);
@@ -1390,6 +1389,11 @@
return configChanged;
}
+ boolean isAdjustedForMinimizedDock() {
+ return mAppToken != null && mAppToken.mTask != null
+ && mAppToken.mTask.mStack.isAdjustedForMinimizedDock();
+ }
+
void removeLocked() {
disposeInputChannel();
@@ -1776,7 +1780,8 @@
return isVisibleOrAdding()
&& (mViewVisibility == View.VISIBLE)
&& ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
- && (mAppToken == null || mAppToken.windowsAreFocusable());
+ && (mAppToken == null || mAppToken.windowsAreFocusable())
+ && !isAdjustedForMinimizedDock();
}
@Override
@@ -2405,8 +2410,8 @@
pw.print(prefix); pw.print("mToken="); pw.println(mToken);
pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
if (mAppToken != null) {
- pw.print(prefix); pw.print("mAppToken="); pw.print(mAppToken);
- pw.print(" isAnimatingWithSavedSurface()=");
+ pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
+ pw.print(prefix); pw.print(" isAnimatingWithSavedSurface()=");
pw.print(isAnimatingWithSavedSurface());
pw.print(" mAppDied=");pw.println(mAppDied);
}
@@ -2491,6 +2496,7 @@
pw.print(" content="); mContentInsets.printShortString(pw);
pw.print(" visible="); mVisibleInsets.printShortString(pw);
pw.print(" stable="); mStableInsets.printShortString(pw);
+ pw.print(" surface="); mAttrs.surfaceInsets.printShortString(pw);
pw.print(" outsets="); mOutsets.printShortString(pw);
pw.println();
pw.print(prefix); pw.print("Lst insets: overscan=");
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9c25f63..0245513 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.StackId;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
@@ -1032,7 +1033,7 @@
// relative to their containing frame. We need to offset the difference
// between the containing frame as used to calculate the crop and our
// bounds to compensate for this.
- if (mWin.isChildWindow() && mWin.layoutInParentFrame()) {
+ if (mWin.layoutInParentFrame()) {
mClipRect.offset( (mWin.mContainingFrame.left - mWin.mFrame.left),
mWin.mContainingFrame.top - mWin.mFrame.top );
}
@@ -1164,8 +1165,8 @@
final float scale = w.mInvGlobalScale;
mSystemDecorRect.left = (int) (mSystemDecorRect.left * scale - 0.5f);
mSystemDecorRect.top = (int) (mSystemDecorRect.top * scale - 0.5f);
- mSystemDecorRect.right = (int) ((mSystemDecorRect.right+1) * scale - 0.5f);
- mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom+1) * scale - 0.5f);
+ mSystemDecorRect.right = (int) ((mSystemDecorRect.right + 1) * scale - 0.5f);
+ mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom + 1) * scale - 0.5f);
}
}
@@ -1178,8 +1179,8 @@
return;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop for window: " + w + ", " + "mLastCrop=" +
- mLastClipRect);
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG,
+ "Updating crop win=" + w + " mLastCrop=" + mLastClipRect);
// Need to recompute a new system decor rect each time.
if (!w.isDefaultDisplay()) {
@@ -1204,8 +1205,8 @@
} else {
// Crop to the system decor specified by policy.
calculateSystemDecorRect();
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop for " + w + ", mDecorFrame="
- + w.mDecorFrame + ", mSystemDecorRect=" + mSystemDecorRect);
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
+ + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
}
final boolean fullscreen = w.isFrameFullscreen(displayInfo);
@@ -1215,8 +1216,8 @@
// We use the clip rect as provided by the tranformation for non-fullscreen windows to
// avoid premature clipping with the system decor rect.
clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : mSystemDecorRect);
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Initial clip rect: " + clipRect + ", mHasClipRect="
- + mHasClipRect + ", fullscreen=" + fullscreen);
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
+ + " mHasClipRect=" + mHasClipRect + " fullscreen=" + fullscreen);
if (isFreeformResizing && !w.isChildWindow()) {
// For freeform resizing non child windows, we are using the big surface positioned
@@ -1243,7 +1244,8 @@
finalClipRect.setEmpty();
adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing);
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + clipRect);
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG,
+ "win=" + w + " Clip rect after stack adjustment=" + clipRect);
w.transformFromScreenToSurfaceSpace(clipRect);
@@ -1254,6 +1256,8 @@
}
void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin
+ + " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
if (!clipRect.equals(mLastClipRect)) {
mLastClipRect.set(clipRect);
mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
@@ -1288,19 +1292,20 @@
}
final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
- if (w == winShowWhenLocked) {
+ if (w == winShowWhenLocked && mPolicy.isKeyguardShowingOrOccluded()) {
return;
}
final TaskStack stack = task.mStack;
stack.getDimBounds(mTmpStackBounds);
+ final Rect surfaceInsets = w.getAttrs().surfaceInsets;
// When we resize we use the big surface approach, which means we can't trust the
// window frame bounds anymore. Instead, the window will be placed at 0, 0, but to avoid
// hardcoding it, we use surface coordinates.
final int frameX = isFreeformResizing ? (int) mSurfaceController.getX() :
- w.mFrame.left + mWin.mXOffset - w.getAttrs().surfaceInsets.left;
+ w.mFrame.left + mWin.mXOffset - surfaceInsets.left;
final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
- w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;
+ w.mFrame.top + mWin.mYOffset - surfaceInsets.top;
// If we are animating, we either apply the clip before applying all the animation
// transformation or after all the transformation.
@@ -1311,6 +1316,15 @@
if (useFinalClipRect) {
finalClipRect.set(mTmpStackBounds);
} else {
+ if (StackId.hasWindowShadow(stack.mStackId)
+ && !StackId.isTaskResizeAllowed(stack.mStackId)) {
+ // The windows in this stack display drop shadows and the fill the entire stack
+ // area. Adjust the stack bounds we will use to cropping take into account the
+ // offsets we use to display the drop shadow so it doesn't get cropped.
+ mTmpStackBounds.inset(-surfaceInsets.left, -surfaceInsets.top,
+ -surfaceInsets.right, -surfaceInsets.bottom);
+ }
+
clipRect.left = Math.max(0,
Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
clipRect.top = Math.max(0,
@@ -1356,21 +1370,19 @@
// past where the system would have cropped us
mTmpClipRect.set(0, 0, mTmpSize.width(), mTmpSize.height());
mTmpFinalClipRect.setEmpty();
- updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
} else {
mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
recoveringMemory);
- updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
}
+ updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * extraHScale,
mDtDx * w.mVScale * extraVScale,
mDsDy * w.mHScale * extraHScale,
mDtDy * w.mVScale * extraVScale, recoveringMemory);
mSurfaceResized = mSurfaceController.setSizeInTransaction(
- mTmpSize.width(), mTmpSize.height(),
- recoveringMemory);
+ mTmpSize.width(), mTmpSize.height(), recoveringMemory);
if (mSurfaceResized) {
mReportSurfaceResized = true;
@@ -1775,7 +1787,7 @@
pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
- pw.print(" mAnimation="); pw.println(mAnimation);
+ pw.print(" mAnimation="); pw.print(mAnimation);
pw.print(" mStackClip="); pw.println(mStackClip);
}
if (mHasTransformation || mHasLocalTransformation) {
@@ -1793,9 +1805,9 @@
pw.print(prefix); pw.print(" mLastHidden="); pw.println(mLastHidden);
pw.print(prefix); pw.print("mSystemDecorRect="); mSystemDecorRect.printShortString(pw);
pw.print(" last="); mLastSystemDecorRect.printShortString(pw);
- if (mHasClipRect) {
- pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
- }
+ pw.print(" mHasClipRect="); pw.print(mHasClipRect);
+ pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
+
if (!mLastFinalClipRect.isEmpty()) {
pw.print(" mLastFinalClipRect="); mLastFinalClipRect.printShortString(pw);
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 78b0844..058b631 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -562,7 +562,7 @@
method_reportNavigationMessages = env->GetMethodID(
clazz,
"reportNavigationMessage",
- "(Landroid/location/GnssNavigationMessageEvent;)V");
+ "(Landroid/location/GnssNavigationMessage;)V");
err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
@@ -1165,7 +1165,7 @@
static jobject translate_gnss_clock(JNIEnv* env, GnssClock* clock) {
JavaObject object(env, "android/location/GnssClock");
- GpsClockFlags flags = clock->flags;
+ GnssClockFlags flags = clock->flags;
SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
LeapSecond,
@@ -1237,9 +1237,10 @@
static jobject translate_gnss_measurement(JNIEnv* env,
GnssMeasurement* measurement) {
JavaObject object(env, "android/location/GnssMeasurement");
- GpsMeasurementFlags flags = measurement->flags;
- SET(Svid, measurement->svid);
+ GnssMeasurementFlags flags = measurement->flags;
+
+ SET(Svid, static_cast<int32_t>(measurement->svid));
SET(ConstellationType, static_cast<int32_t>(measurement->constellation));
SET(TimeOffsetNanos, measurement->time_offset_ns);
SET(State, static_cast<int32_t>(measurement->state));
@@ -1379,8 +1380,8 @@
ALOGE("Invalid data provided to gps_measurement_callback");
return;
}
- if (data->size != sizeof(GpsData)) {
- ALOGE("Invalid GpsData size found in gps_measurement_callback, "
+ if (data->size != sizeof(GnssData)) {
+ ALOGE("Invalid GnssData size found in gnss_measurement_callback, "
"size=%zd",
data->size);
return;
@@ -1486,26 +1487,6 @@
return object.get();
}
-static void set_navigation_message(jobject navigationMessage) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- jclass navigationMessageEventClass =
- env->FindClass("android/location/GnssNavigationMessageEvent");
- jmethodID navigationMessageEventCtor = env->GetMethodID(
- navigationMessageEventClass,
- "<init>",
- "(Landroid/location/GnssNavigationMessage;)V");
- jobject navigationMessageEvent = env->NewObject(
- navigationMessageEventClass,
- navigationMessageEventCtor,
- navigationMessage);
- env->CallVoidMethod(mCallbacksObj,
- method_reportNavigationMessages,
- navigationMessageEvent);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- env->DeleteLocalRef(navigationMessageEventClass);
- env->DeleteLocalRef(navigationMessageEvent);
-}
-
static void navigation_message_callback(GpsNavigationMessage* message) {
if (message == NULL) {
ALOGE("Invalid Navigation Message provided to callback");
@@ -1517,7 +1498,9 @@
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
jobject navigationMessage = translate_gps_navigation_message(env, message);
- set_navigation_message(navigationMessage);
+ env->CallVoidMethod(mCallbacksObj,
+ method_reportNavigationMessages,
+ navigationMessage);
env->DeleteLocalRef(navigationMessage);
}
@@ -1532,7 +1515,9 @@
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
jobject navigationMessage = translate_gnss_navigation_message(env, message);
- set_navigation_message(navigationMessage);
+ env->CallVoidMethod(mCallbacksObj,
+ method_reportNavigationMessages,
+ navigationMessage);
env->DeleteLocalRef(navigationMessage);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d229633..d3d05f3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -211,7 +211,7 @@
private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
- private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
+ private static final int MONITORING_CERT_NOTIFICATION_ID = R.plurals.ssl_ca_cert_warning;
private static final int PROFILE_WIPED_NOTIFICATION_ID = 1001;
private static final String ATTR_PERMISSION_PROVIDER = "permission-provider";
@@ -655,8 +655,8 @@
Bundle userRestrictions;
// Support text provided by the admin to display to the user.
- String shortSupportMessage = null;
- String longSupportMessage = null;
+ CharSequence shortSupportMessage = null;
+ CharSequence longSupportMessage = null;
// Background color of confirm credentials screen. Default: teal.
static final int DEF_ORGANIZATION_COLOR = Color.parseColor("#00796B");
@@ -870,12 +870,12 @@
}
if (!TextUtils.isEmpty(shortSupportMessage)) {
out.startTag(null, TAG_SHORT_SUPPORT_MESSAGE);
- out.text(shortSupportMessage);
+ out.text(shortSupportMessage.toString());
out.endTag(null, TAG_SHORT_SUPPORT_MESSAGE);
}
if (!TextUtils.isEmpty(longSupportMessage)) {
out.startTag(null, TAG_LONG_SUPPORT_MESSAGE);
- out.text(longSupportMessage);
+ out.text(longSupportMessage.toString());
out.endTag(null, TAG_LONG_SUPPORT_MESSAGE);
}
if (parentAdmin != null) {
@@ -2696,23 +2696,25 @@
// Build and show a warning notification
int smallIconId;
String contentText;
- // TODO Why does it use the DO name? The cert APIs are all for PO. b/25772443
- final String ownerName = getDeviceOwnerName();
- if (isManagedProfile(userHandle.getIdentifier())) {
- contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_administrator);
+ if (getProfileOwner(userHandle.getIdentifier()) != null) {
+ contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed,
+ getProfileOwnerName(userHandle.getIdentifier()));
smallIconId = R.drawable.stat_sys_certificate_info;
- } else if (ownerName != null) {
- contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed, ownerName);
+ } else if (getDeviceOwnerUserId() == userHandle.getIdentifier()) {
+ contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed,
+ getDeviceOwnerName());
smallIconId = R.drawable.stat_sys_certificate_info;
} else {
contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_unknown);
smallIconId = android.R.drawable.stat_sys_warning;
}
+ final int numberOfCertificates = pendingCertificates.size();
Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
dialogIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
dialogIntent.setPackage("com.android.settings");
+ dialogIntent.putExtra(Settings.EXTRA_NUMBER_OF_CERTIFICATES, numberOfCertificates);
PendingIntent notifyIntent = PendingIntent.getActivityAsUser(mContext, 0,
dialogIntent, PendingIntent.FLAG_UPDATE_CURRENT, null, userHandle);
@@ -2726,7 +2728,8 @@
}
final Notification noti = new Notification.Builder(userContext)
.setSmallIcon(smallIconId)
- .setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning))
+ .setContentTitle(mContext.getResources().getQuantityText(
+ R.plurals.ssl_ca_cert_warning, numberOfCertificates))
.setContentText(contentText)
.setContentIntent(notifyIntent)
.setPriority(Notification.PRIORITY_HIGH)
@@ -8501,7 +8504,7 @@
}
@Override
- public void setShortSupportMessage(@NonNull ComponentName who, String message) {
+ public void setShortSupportMessage(@NonNull ComponentName who, CharSequence message) {
if (!mHasFeature) {
return;
}
@@ -8518,7 +8521,7 @@
}
@Override
- public String getShortSupportMessage(@NonNull ComponentName who) {
+ public CharSequence getShortSupportMessage(@NonNull ComponentName who) {
if (!mHasFeature) {
return null;
}
@@ -8531,7 +8534,7 @@
}
@Override
- public void setLongSupportMessage(@NonNull ComponentName who, String message) {
+ public void setLongSupportMessage(@NonNull ComponentName who, CharSequence message) {
if (!mHasFeature) {
return;
}
@@ -8548,7 +8551,7 @@
}
@Override
- public String getLongSupportMessage(@NonNull ComponentName who) {
+ public CharSequence getLongSupportMessage(@NonNull ComponentName who) {
if (!mHasFeature) {
return null;
}
@@ -8561,7 +8564,7 @@
}
@Override
- public String getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+ public CharSequence getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
if (!mHasFeature) {
return null;
}
@@ -8579,7 +8582,7 @@
}
@Override
- public String getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+ public CharSequence getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
if (!mHasFeature) {
return null;
}
@@ -8657,7 +8660,7 @@
}
@Override
- public void setOrganizationName(@NonNull ComponentName who, String text) {
+ public void setOrganizationName(@NonNull ComponentName who, CharSequence text) {
if (!mHasFeature) {
return;
}
@@ -8668,14 +8671,15 @@
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
if (!TextUtils.equals(admin.organizationName, text)) {
- admin.organizationName = TextUtils.nullIfEmpty(text);
+ admin.organizationName = (text == null || text.length() == 0)
+ ? null : text.toString();
saveSettingsLocked(userHandle);
}
}
}
@Override
- public String getOrganizationName(@NonNull ComponentName who) {
+ public CharSequence getOrganizationName(@NonNull ComponentName who) {
if (!mHasFeature) {
return null;
}
@@ -8689,7 +8693,7 @@
}
@Override
- public String getOrganizationNameForUser(int userHandle) {
+ public CharSequence getOrganizationNameForUser(int userHandle) {
if (!mHasFeature) {
return null;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6f45508..8c2f559 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -18,7 +18,6 @@
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
-import android.app.IAlarmManager;
import android.app.INotificationManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
@@ -55,13 +54,11 @@
import com.android.internal.os.ZygoteInit;
import com.android.internal.widget.ILockSettings;
import com.android.server.accessibility.AccessibilityManagerService;
-import com.android.server.accounts.AccountManagerService;
import com.android.server.am.ActivityManagerService;
import com.android.server.audio.AudioService;
import com.android.server.camera.CameraService;
import com.android.server.clipboard.ClipboardService;
import com.android.server.connectivity.MetricsLoggerService;
-import com.android.server.content.ContentService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
@@ -97,7 +94,6 @@
import com.android.server.twilight.TwilightService;
import com.android.server.usage.UsageStatsService;
import com.android.server.vr.VrManagerService;
-import com.android.server.wallpaper.WallpaperManagerService;
import com.android.server.webkit.WebViewUpdateService;
import com.android.server.wm.WindowManagerService;
@@ -157,8 +153,12 @@
"com.google.android.clockwork.ThermalObserver";
private static final String WEAR_BLUETOOTH_SERVICE_CLASS =
"com.google.android.clockwork.bluetooth.WearBluetoothService";
+ private static final String ACCOUNT_SERVICE_CLASS =
+ "com.android.server.accounts.AccountManagerService$Lifecycle";
private static final String CONTENT_SERVICE_CLASS =
"com.android.server.content.ContentService$Lifecycle";
+ private static final String WALLPAPER_SERVICE_CLASS =
+ "com.android.server.wallpaper.WallpaperManagerService$Lifecycle";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
@@ -187,6 +187,7 @@
private PackageManagerService mPackageManagerService;
private PackageManager mPackageManager;
private ContentResolver mContentResolver;
+ private EntropyMixer mEntropyMixer;
private boolean mOnlyCore;
private boolean mFirstBoot;
@@ -497,10 +498,7 @@
*/
private void startOtherServices() {
final Context context = mSystemContext;
- AccountManagerService accountManager = null;
- ContentService contentService = null;
VibratorService vibrator = null;
- IAlarmManager alarm = null;
IMountService mountService = null;
NetworkManagementService networkManagement = null;
NetworkStatsService networkStats = null;
@@ -516,8 +514,6 @@
TelephonyRegistry telephonyRegistry = null;
ConsumerIrService consumerIr = null;
MmsServiceBroker mmsService = null;
- EntropyMixer entropyMixer = null;
- VrManagerService vrManagerService = null;
HardwarePropertiesManagerService hardwarePropertiesService = null;
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
@@ -556,7 +552,7 @@
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartEntropyMixer");
- entropyMixer = new EntropyMixer(context);
+ mEntropyMixer = new EntropyMixer(context);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
mContentResolver = context.getContentResolver();
@@ -566,13 +562,7 @@
// The AccountManager must come before the ContentService
traceBeginAndSlog("StartAccountManagerService");
- try {
- // TODO: seems like this should be disable-able, but req'd by ContentService
- accountManager = new AccountManagerService(context);
- ServiceManager.addService(Context.ACCOUNT_SERVICE, accountManager);
- } catch (Throwable e) {
- Slog.e(TAG, "Failure starting Account Manager", e);
- }
+ mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartContentService");
@@ -593,9 +583,9 @@
ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ traceBeginAndSlog("StartAlarmManagerService");
mSystemServiceManager.startService(AlarmManagerService.class);
- alarm = IAlarmManager.Stub.asInterface(
- ServiceManager.getService(Context.ALARM_SERVICE));
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("InitWatchdog");
final Watchdog watchdog = Watchdog.getInstance();
@@ -652,7 +642,6 @@
StatusBarManagerService statusBar = null;
INotificationManager notification = null;
- WallpaperManagerService wallpaper = null;
LocationManagerService location = null;
CountryDetectorService countryDetector = null;
ILockSettings lockSettings = null;
@@ -886,24 +875,6 @@
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeAccountManagerServiceReady");
- try {
- if (accountManager != null)
- accountManager.systemReady();
- } catch (Throwable e) {
- reportWtf("making Account Manager Service ready", e);
- }
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeContentServiceReady");
- try {
- if (contentService != null)
- contentService.systemReady();
- } catch (Throwable e) {
- reportWtf("making Content Service ready", e);
- }
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-
mSystemServiceManager.startService(NotificationManagerService.class);
notification = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -946,12 +917,7 @@
if (!disableNonCoreServices && context.getResources().getBoolean(
R.bool.config_enableWallpaperService)) {
traceBeginAndSlog("StartWallpaperManagerService");
- try {
- wallpaper = new WallpaperManagerService(context);
- ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
- } catch (Throwable e) {
- reportWtf("starting Wallpaper Service", e);
- }
+ mSystemServiceManager.startService(WALLPAPER_SERVICE_CLASS);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
@@ -1278,12 +1244,10 @@
final NetworkPolicyManagerService networkPolicyF = networkPolicy;
final ConnectivityService connectivityF = connectivity;
final NetworkScoreService networkScoreF = networkScore;
- final WallpaperManagerService wallpaperF = wallpaper;
final LocationManagerService locationF = location;
final CountryDetectorService countryDetectorF = countryDetector;
final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
- final StatusBarManagerService statusBarF = statusBar;
final AssetAtlasService atlasF = atlas;
final InputManagerService inputManagerF = inputManager;
final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
@@ -1371,11 +1335,6 @@
SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
try {
- if (wallpaperF != null) wallpaperF.systemRunning();
- } catch (Throwable e) {
- reportWtf("Notifying WallpaperService running", e);
- }
- try {
if (locationF != null) locationF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying Location Service running", e);
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 406dd56..804fa03 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -336,17 +336,17 @@
class ReceiveThread extends Thread {
private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH];
- private boolean stopped = false;
+ private volatile boolean mStopped = false;
public void halt() {
- stopped = true;
+ mStopped = true;
closeSockets(); // Interrupts the read() call the thread is blocked in.
}
@Override
public void run() {
if (DBG) Log.d(TAG, "Receive thread started");
- while (!stopped) {
+ while (!mStopped) {
int length = 0; // Or compiler can't tell it's initialized if a parse error occurs.
try {
length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
@@ -355,7 +355,7 @@
if (DBG) Log.d(TAG, "Received packet: " + packet);
sendMessage(CMD_RECEIVED_PACKET, packet);
} catch (IOException|ErrnoException e) {
- if (!stopped) {
+ if (!mStopped) {
Log.e(TAG, "Read error", e);
}
DhcpClientEvent.logEvent(IpConnectivityEvent.IPCE_DHCP_RECV_ERROR,
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index a881408..b184fe5 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -3,6 +3,7 @@
import android.net.DhcpResults;
import android.net.LinkAddress;
import android.net.NetworkUtils;
+import android.net.metrics.DhcpErrorEvent;
import android.os.Build;
import android.os.SystemProperties;
import android.system.OsConstants;
@@ -765,6 +766,7 @@
// check to see if we need to parse L2, IP, and UDP encaps
if (pktType == ENCAP_L2) {
if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L2_TOO_SHORT);
throw new ParseException("L2 packet too short, %d < %d",
packet.remaining(), MIN_PACKET_LENGTH_L2);
}
@@ -777,13 +779,16 @@
short l2type = packet.getShort();
- if (l2type != OsConstants.ETH_P_IP)
+ if (l2type != OsConstants.ETH_P_IP) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L2_WRONG_ETH_TYPE);
throw new ParseException("Unexpected L2 type 0x%04x, expected 0x%04x",
l2type, OsConstants.ETH_P_IP);
+ }
}
if (pktType <= ENCAP_L3) {
if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_TOO_SHORT);
throw new ParseException("L3 packet too short, %d < %d",
packet.remaining(), MIN_PACKET_LENGTH_L3);
}
@@ -791,6 +796,7 @@
byte ipTypeAndLength = packet.get();
int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
if (ipVersion != 4) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_NOT_IPV4);
throw new ParseException("Invalid IP version %d", ipVersion);
}
@@ -808,6 +814,7 @@
ipDst = readIpAddress(packet);
if (ipProto != IP_TYPE_UDP) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L4_NOT_UDP);
throw new ParseException("Protocol not UDP: %d", ipProto);
}
@@ -834,12 +841,14 @@
// socket to drop packets that don't have the right source ports. However, it's
// possible that a packet arrives between when the socket is bound and when the
// filter is set. http://b/26696823 .
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L4_WRONG_PORT);
throw new ParseException("Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
}
}
// We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.BOOTP_TOO_SHORT);
throw new ParseException("Invalid type or BOOTP packet too short, %d < %d",
packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
}
@@ -864,6 +873,7 @@
packet.get(ipv4addr);
relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
} catch (UnknownHostException ex) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_INVALID_IP);
throw new ParseException("Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
}
@@ -888,6 +898,7 @@
int dhcpMagicCookie = packet.getInt();
if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE);
throw new ParseException("Bad magic cookie 0x%08x, should be 0x%08x", dhcpMagicCookie,
DHCP_MAGIC_COOKIE);
}
@@ -896,9 +907,8 @@
boolean notFinishedOptions = true;
while ((packet.position() < packet.limit()) && notFinishedOptions) {
+ final byte optionType = packet.get(); // cannot underflow because position < limit
try {
- byte optionType = packet.get();
-
if (optionType == DHCP_OPTION_END) {
notFinishedOptions = false;
} else if (optionType == DHCP_OPTION_PAD) {
@@ -999,11 +1009,14 @@
}
if (expectedLen != optionLen) {
+ DhcpErrorEvent.logEvent(
+ DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
throw new ParseException("Invalid length %d for option %d, expected %d",
optionLen, optionType, expectedLen);
}
}
} catch (BufferUnderflowException e) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
throw new ParseException("BufferUnderflowException");
}
}
@@ -1012,6 +1025,7 @@
switch(dhcpType) {
case (byte) 0xFF:
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_NO_MSG_TYPE);
throw new ParseException("No DHCP message type option");
case DHCP_MESSAGE_TYPE_DISCOVER:
newPacket = new DhcpDiscoverPacket(
@@ -1045,6 +1059,7 @@
clientMac);
break;
default:
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE);
throw new ParseException("Unimplemented DHCP type %d", dhcpType);
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 54aeb3d..59ebf1b 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -30,10 +30,12 @@
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
import android.net.dhcp.DhcpClient;
+import android.net.metrics.IpManagerEvent;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -52,6 +54,10 @@
import java.net.SocketException;
import java.util.Objects;
+import static android.net.metrics.IpConnectivityEvent.IPCE_IPMGR_PROVISIONING_OK;
+import static android.net.metrics.IpConnectivityEvent.IPCE_IPMGR_PROVISIONING_FAIL;
+import static android.net.metrics.IpConnectivityEvent.IPCE_IPMGR_COMPLETE_LIFECYCLE;
+
/**
* IpManager
@@ -264,6 +270,7 @@
private ProxyInfo mHttpProxy;
private ApfFilter mApfFilter;
private boolean mMulticastFiltering;
+ private long mStartTimeMillis;
/**
* Member variables accessed both from within the StateMachine thread
@@ -355,6 +362,8 @@
public void startProvisioning(ProvisioningConfiguration req) {
getNetworkInterface();
+
+ mCallback.setNeighborDiscoveryOffload(true);
sendMessage(CMD_START, new ProvisioningConfiguration(req));
}
@@ -477,6 +486,12 @@
}
}
+ private void recordMetric(final int type) {
+ if (mStartTimeMillis <= 0) { Log.wtf(mTag, "Start time undefined!"); }
+ IpManagerEvent.logEvent(type, mInterfaceName,
+ SystemClock.elapsedRealtime() - mStartTimeMillis);
+ }
+
// For now: use WifiStateMachine's historical notion of provisioned.
private static boolean isProvisioned(LinkProperties lp) {
// For historical reasons, we should connect even if all we have is
@@ -534,6 +549,16 @@
delta = ProvisioningChange.LOST_PROVISIONING;
}
+ // Additionally:
+ //
+ // If the previous link properties had a global IPv6 address and an
+ // IPv6 default route then also consider the loss of that default route
+ // to be a loss of provisioning. See b/27962810.
+ if (oldLp.hasGlobalIPv6Address() && oldLp.hasIPv6DefaultRoute() &&
+ !newLp.hasIPv6DefaultRoute()) {
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
return delta;
}
@@ -542,11 +567,13 @@
switch (delta) {
case GAINED_PROVISIONING:
if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
+ recordMetric(IPCE_IPMGR_PROVISIONING_OK);
mCallback.onProvisioningSuccess(newLp);
break;
case LOST_PROVISIONING:
if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+ recordMetric(IPCE_IPMGR_PROVISIONING_FAIL);
mCallback.onProvisioningFailure(newLp);
break;
@@ -722,6 +749,10 @@
}
resetLinkProperties();
+ if (mStartTimeMillis > 0) {
+ recordMetric(IPCE_IPMGR_COMPLETE_LIFECYCLE);
+ mStartTimeMillis = 0;
+ }
}
@Override
@@ -792,11 +823,16 @@
class StartedState extends State {
@Override
public void enter() {
+ mStartTimeMillis = SystemClock.elapsedRealtime();
+
mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
mCallback, mMulticastFiltering);
// TODO: investigate the effects of any multicast filtering racing/interfering with the
// rest of this IP configuration startup.
- if (mApfFilter == null) mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+ if (mApfFilter == null) {
+ mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+ }
+
// Set privacy extensions.
try {
mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
@@ -827,6 +863,7 @@
handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
} else {
if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+ recordMetric(IPCE_IPMGR_PROVISIONING_FAIL);
mCallback.onProvisioningFailure(getLinkProperties());
transitionTo(mStoppingState);
}
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index af3175a..c8dbe02 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -26,6 +26,7 @@
import android.net.RouteInfo;
import android.net.metrics.IpReachabilityMonitorMessageEvent;
import android.net.metrics.IpReachabilityMonitorProbeEvent;
+import android.net.metrics.IpReachabilityMonitorLostEvent;
import android.net.netlink.NetlinkConstants;
import android.net.netlink.NetlinkErrorMessage;
import android.net.netlink.NetlinkMessage;
@@ -353,6 +354,7 @@
}
if (delta == ProvisioningChange.LOST_PROVISIONING) {
+ IpReachabilityMonitorLostEvent.logEvent(mInterfaceName);
final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
Log.w(TAG, logMsg);
if (mCallback != null) {
@@ -521,7 +523,7 @@
final short msgType = neighMsg.getHeader().nlmsg_type;
final short nudState = ndMsg.ndm_state;
- IpReachabilityMonitorMessageEvent.logEvent(maybeGetInterfaceName(mInterfaceIndex),
+ IpReachabilityMonitorMessageEvent.logEvent(mInterfaceName,
destination.getHostAddress(), msgType, nudState);
final String eventMsg = "NeighborEvent{"
+ "elapsedMs=" + whenMs + ", "
@@ -553,11 +555,4 @@
}
}
}
-
- private String maybeGetInterfaceName(int index) {
- if (index == mInterfaceIndex) {
- return mInterfaceName;
- }
- return "ifindex-" + index;
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 2f20a4b..26eed24 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -70,6 +70,7 @@
import com.android.internal.util.WakeupMessage;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
import com.android.server.net.NetworkPinner;
import java.net.InetAddress;
@@ -223,11 +224,15 @@
private final NetworkCapabilities mNetworkCapabilities;
private final IdleableHandlerThread mHandlerThread;
private final ConditionVariable mDisconnected = new ConditionVariable();
+ private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
private int mScore;
private NetworkAgent mNetworkAgent;
private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED;
private int mStopKeepaliveError = PacketKeepalive.NO_KEEPALIVE;
private Integer mExpectedKeepaliveSlot = null;
+ // Contains the redirectUrl from networkStatus(). Before reading, wait for
+ // mNetworkStatusReceived.
+ private String mRedirectUrl;
MockNetworkAgent(int transport) {
final int type = transportToLegacyType(transport);
@@ -266,6 +271,12 @@
public void stopPacketKeepalive(Message msg) {
onPacketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
}
+
+ @Override
+ public void networkStatus(int status, String redirectUrl) {
+ mRedirectUrl = redirectUrl;
+ mNetworkStatusReceived.open();
+ }
};
// Waits for the NetworkAgent to be registered, which includes the creation of the
// NetworkMonitor.
@@ -340,13 +351,15 @@
if (callback != null) mCm.unregisterNetworkCallback(callback);
}
- public void connectWithCaptivePortal() {
+ public void connectWithCaptivePortal(String redirectUrl) {
mWrappedNetworkMonitor.gen204ProbeResult = 200;
+ mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl;
connect(false);
waitFor(new Criteria() { public boolean get() {
NetworkCapabilities caps = mCm.getNetworkCapabilities(getNetwork());
return caps != null && caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL);} });
mWrappedNetworkMonitor.gen204ProbeResult = 500;
+ mWrappedNetworkMonitor.gen204ProbeRedirectUrl = null;
}
public void disconnect() {
@@ -381,6 +394,11 @@
public void setExpectedKeepaliveSlot(Integer slot) {
mExpectedKeepaliveSlot = slot;
}
+
+ public String waitForRedirectUrl() {
+ assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS));
+ return mRedirectUrl;
+ }
}
/**
@@ -543,6 +561,7 @@
private class WrappedNetworkMonitor extends NetworkMonitor {
// HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
public int gen204ProbeResult = 500;
+ public String gen204ProbeRedirectUrl = null;
public WrappedNetworkMonitor(Context context, Handler handler,
NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest) {
@@ -550,8 +569,8 @@
}
@Override
- protected int isCaptivePortal() {
- return gen204ProbeResult;
+ protected CaptivePortalProbeResult isCaptivePortal() {
+ return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl);
}
@Override
@@ -1344,8 +1363,10 @@
// Bring up a network with a captive portal.
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithCaptivePortal();
+ String firstRedirectUrl = "http://example.com/firstPath";
+ mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
captivePortalCallback.expectCallback(CallbackState.AVAILABLE);
+ assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
// Take down network.
// Expect onLost callback.
@@ -1355,8 +1376,10 @@
// Bring up a network with a captive portal.
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithCaptivePortal();
+ String secondRedirectUrl = "http://example.com/secondPath";
+ mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
captivePortalCallback.expectCallback(CallbackState.AVAILABLE);
+ assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
// Make captive portal disappear then revalidate.
// Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
index 2fd11da..ce02a79 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
@@ -216,7 +216,8 @@
String injectShortcutManagerConstants() {
return ConfigConstants.KEY_RESET_INTERVAL_SEC + "=" + (INTERVAL / 1000) + ","
+ ConfigConstants.KEY_MAX_SHORTCUTS + "=" + MAX_SHORTCUTS + ","
- + ConfigConstants.KEY_MAX_DAILY_UPDATES + "=" + MAX_DAILY_UPDATES + ","
+ + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "="
+ + MAX_UPDATES_PER_INTERVAL + ","
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=" + MAX_ICON_DIMENSION + ","
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "="
+ MAX_ICON_DIMENSION_LOWRAM + ","
@@ -465,7 +466,7 @@
private static final int MAX_SHORTCUTS = 10;
- private static final int MAX_DAILY_UPDATES = 3;
+ private static final int MAX_UPDATES_PER_INTERVAL = 3;
private static final int MAX_ICON_DIMENSION = 128;
@@ -1074,7 +1075,7 @@
assertResetTimes(START_TIME + INTERVAL, START_TIME + 2 * INTERVAL);
- // Advance further; 4 days since start.
+ // Advance further; 4 hours since start.
mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL + 50;
assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
@@ -1111,14 +1112,14 @@
mService.updateConfigurationLocked(
ConfigConstants.KEY_RESET_INTERVAL_SEC + "=123,"
+ ConfigConstants.KEY_MAX_SHORTCUTS + "=4,"
- + ConfigConstants.KEY_MAX_DAILY_UPDATES + "=5,"
+ + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=5,"
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
+ ConfigConstants.KEY_ICON_FORMAT + "=WEBP,"
+ ConfigConstants.KEY_ICON_QUALITY + "=75");
assertEquals(123000, mService.getResetIntervalForTest());
assertEquals(4, mService.getMaxDynamicShortcutsForTest());
- assertEquals(5, mService.getMaxDailyUpdatesForTest());
+ assertEquals(5, mService.getMaxUpdatesPerIntervalForTest());
assertEquals(100, mService.getMaxIconDimensionForTest());
assertEquals(CompressFormat.WEBP, mService.getIconPersistFormatForTest());
assertEquals(75, mService.getIconPersistQualityForTest());
@@ -1134,8 +1135,8 @@
assertEquals(ShortcutService.DEFAULT_MAX_SHORTCUTS_PER_APP,
mService.getMaxDynamicShortcutsForTest());
- assertEquals(ShortcutService.DEFAULT_MAX_DAILY_UPDATES,
- mService.getMaxDailyUpdatesForTest());
+ assertEquals(ShortcutService.DEFAULT_MAX_UPDATES_PER_INTERVAL,
+ mService.getMaxUpdatesPerIntervalForTest());
assertEquals(50, mService.getMaxIconDimensionForTest());
@@ -1154,7 +1155,7 @@
/** Test for {@link android.content.pm.ShortcutManager#getRemainingCallCount()} */
public void testGetRemainingCallCount() {
- assertEquals(MAX_DAILY_UPDATES, mManager.getRemainingCallCount());
+ assertEquals(MAX_UPDATES_PER_INTERVAL, mManager.getRemainingCallCount());
}
/** Test for {@link android.content.pm.ShortcutManager#getRateLimitResetTime()} */
@@ -1241,61 +1242,71 @@
mManager.getDynamicShortcuts()),
"shortcut1");
- assertTrue(mManager.addDynamicShortcut(si2));
+ assertTrue(mManager.addDynamicShortcuts(list(si2, si3)));
assertEquals(1, mManager.getRemainingCallCount());
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut1", "shortcut2");
+ "shortcut1", "shortcut2", "shortcut3");
- // Add with the same ID
- assertTrue(mManager.addDynamicShortcut(makeShortcut("shortcut1")));
+ // This should not crash. It'll still consume the quota.
+ assertTrue(mManager.addDynamicShortcuts(list()));
assertEquals(0, mManager.getRemainingCallCount());
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut1", "shortcut2");
+ "shortcut1", "shortcut2", "shortcut3");
+
+ mInjectedCurrentTimeLillis += INTERVAL; // reset
+
+ // Add with the same ID
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("shortcut1"))));
+ assertEquals(2, mManager.getRemainingCallCount());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut1", "shortcut2", "shortcut3");
// TODO Check max number
// TODO Check fields.
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
});
}
- public void testDeleteDynamicShortcut() {
+ public void testDeleteDynamicShortcuts() {
final ShortcutInfo si1 = makeShortcut("shortcut1");
final ShortcutInfo si2 = makeShortcut("shortcut2");
final ShortcutInfo si3 = makeShortcut("shortcut3");
+ final ShortcutInfo si4 = makeShortcut("shortcut4");
- assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3, si4)));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut1", "shortcut2", "shortcut3");
+ "shortcut1", "shortcut2", "shortcut3", "shortcut4");
assertEquals(2, mManager.getRemainingCallCount());
- mManager.deleteDynamicShortcut("shortcut1");
+ mManager.removeDynamicShortcuts(list("shortcut1"));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut2", "shortcut3");
+ "shortcut2", "shortcut3", "shortcut4");
- mManager.deleteDynamicShortcut("shortcut1");
+ mManager.removeDynamicShortcuts(list("shortcut1"));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut2", "shortcut3");
+ "shortcut2", "shortcut3", "shortcut4");
- mManager.deleteDynamicShortcut("shortcutXXX");
+ mManager.removeDynamicShortcuts(list("shortcutXXX"));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut2", "shortcut3");
+ "shortcut2", "shortcut3", "shortcut4");
- mManager.deleteDynamicShortcut("shortcut2");
+ mManager.removeDynamicShortcuts(list("shortcut2", "shortcut4"));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
"shortcut3");
- mManager.deleteDynamicShortcut("shortcut3");
+ mManager.removeDynamicShortcuts(list("shortcut3"));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()));
@@ -1315,7 +1326,7 @@
assertEquals(2, mManager.getRemainingCallCount());
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
assertEquals(0, mManager.getDynamicShortcuts().size());
assertEquals(2, mManager.getRemainingCallCount());
@@ -1383,7 +1394,7 @@
assertEquals(0, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
- // 4 days later...
+ // 4 hours later...
mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL;
assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(2, mManager.getRemainingCallCount());
@@ -1791,13 +1802,13 @@
getCallingUser());
});
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- mManager.deleteDynamicShortcut("s1");
- mManager.deleteDynamicShortcut("s2");
+ mManager.removeDynamicShortcuts(list("s1"));
+ mManager.removeDynamicShortcuts(list("s2"));
});
runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
- mManager.deleteDynamicShortcut("s1");
- mManager.deleteDynamicShortcut("s3");
- mManager.deleteDynamicShortcut("s5");
+ mManager.removeDynamicShortcuts(list("s1"));
+ mManager.removeDynamicShortcuts(list("s3"));
+ mManager.removeDynamicShortcuts(list("s5"));
});
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
assertShortcutIds(assertAllDynamic(
@@ -2089,7 +2100,7 @@
// Delete some.
setCaller(CALLING_PACKAGE_1);
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
- mManager.deleteDynamicShortcut("s2");
+ mManager.removeDynamicShortcuts(list("s2"));
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
dumpsysOnLogcat();
@@ -2154,19 +2165,19 @@
// Delete some.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
- mManager.deleteDynamicShortcut("s2");
+ mManager.removeDynamicShortcuts(list("s2"));
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
- mManager.deleteDynamicShortcut("s3");
+ mManager.removeDynamicShortcuts(list("s3"));
assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
});
runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
- mManager.deleteDynamicShortcut("s2");
+ mManager.removeDynamicShortcuts(list("s2"));
assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
});
@@ -2218,7 +2229,7 @@
// Delete some.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
- mManager.deleteDynamicShortcut("s3");
+ mManager.removeDynamicShortcuts(list("s3"));
assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
});
@@ -2226,8 +2237,8 @@
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
- mManager.deleteDynamicShortcut("s1");
- mManager.deleteDynamicShortcut("s3");
+ mManager.removeDynamicShortcuts(list("s1"));
+ mManager.removeDynamicShortcuts(list("s3"));
assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
});
@@ -2336,13 +2347,13 @@
// Delete all dynamic.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
assertEquals(0, mManager.getDynamicShortcuts().size());
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
assertEquals(0, mManager.getDynamicShortcuts().size());
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2", "s1");
@@ -2377,7 +2388,7 @@
});
// Re-publish s1.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
@@ -2979,7 +2990,7 @@
// Just to make it complicated, delete some.
setCaller(CALLING_PACKAGE_1);
- mManager.deleteDynamicShortcut("s2");
+ mManager.removeDynamicShortcuts(list("s2"));
// intent and check.
setCaller(LAUNCHER_1);
@@ -3051,11 +3062,11 @@
any(UserHandle.class)
);
- // Test for addDynamicShortcut.
+ // Test for addDynamicShortcuts.
reset(c0);
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- dumpsysOnLogcat("before addDynamicShortcut");
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s4")));
+ dumpsysOnLogcat("before addDynamicShortcuts");
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s4"))));
});
waitOnMainThread();
@@ -3071,7 +3082,7 @@
// Test for remove
reset(c0);
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- mManager.deleteDynamicShortcut("s1");
+ mManager.removeDynamicShortcuts(list("s1"));
});
waitOnMainThread();
@@ -3104,7 +3115,7 @@
// Test for deleteAll
reset(c0);
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
});
waitOnMainThread();
@@ -3178,7 +3189,7 @@
resetAll(all);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- mManager.deleteDynamicShortcut("x");
+ mManager.removeDynamicShortcuts(list());
});
waitOnMainThread();
@@ -3195,7 +3206,7 @@
resetAll(all);
runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
- mManager.deleteDynamicShortcut("x");
+ mManager.removeDynamicShortcuts(list());
});
waitOnMainThread();
@@ -3213,7 +3224,7 @@
resetAll(all);
runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
- mManager.deleteDynamicShortcut("x");
+ mManager.removeDynamicShortcuts(list());
});
waitOnMainThread();
@@ -3233,7 +3244,7 @@
resetAll(all);
runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
- mManager.deleteDynamicShortcut("x");
+ mManager.removeDynamicShortcuts(list());
});
waitOnMainThread();
@@ -3253,7 +3264,7 @@
resetAll(all);
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
- mManager.deleteDynamicShortcut("x");
+ mManager.removeDynamicShortcuts(list());
});
waitOnMainThread();
@@ -3477,16 +3488,16 @@
// Remove all dynamic shortcuts; now all shortcuts are just pinned.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
});
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
});
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
});
@@ -4009,22 +4020,22 @@
public void testHandlePackageDelete() {
setCaller(CALLING_PACKAGE_1, USER_0);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
setCaller(CALLING_PACKAGE_2, USER_0);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
setCaller(CALLING_PACKAGE_3, USER_0);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
setCaller(CALLING_PACKAGE_1, USER_10);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
setCaller(CALLING_PACKAGE_2, USER_10);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
setCaller(CALLING_PACKAGE_3, USER_10);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
@@ -4980,6 +4991,7 @@
.setTitle("title")
.setText("text")
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setWeight(123)
.setExtras(pb)
.build();
@@ -4995,6 +5007,7 @@
assertEquals("content://a.b.c/", si.getIcon().getUriString());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
@@ -5016,6 +5029,7 @@
.setIcon(Icon.createWithContentUri("content://a.b.c/"))
.setTitle("title")
.setText("text")
+ .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setExtras(pb)
@@ -5034,6 +5048,7 @@
assertEquals("content://a.b.c/", si.getIcon().getUriString());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
@@ -5051,6 +5066,7 @@
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
@@ -5058,7 +5074,8 @@
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
assertEquals(null, si.getBitmapPath());
- assertEquals(0, si.getIconResourceId());
+
+ assertEquals(456, si.getIconResourceId());
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
@@ -5068,13 +5085,15 @@
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals(null, si.getIntent());
assertEquals(123, si.getWeight());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
assertEquals(null, si.getBitmapPath());
- assertEquals(0, si.getIconResourceId());
+
+ assertEquals(456, si.getIconResourceId());
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
@@ -5084,13 +5103,56 @@
assertEquals(null, si.getIcon());
assertEquals(null, si.getTitle());
assertEquals(null, si.getText());
+ assertEquals(null, si.getCategories());
assertEquals(null, si.getIntent());
assertEquals(0, si.getWeight());
assertEquals(null, si.getExtras());
assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
assertEquals(null, si.getBitmapPath());
- assertEquals(0, si.getIconResourceId());
+
+ assertEquals(456, si.getIconResourceId());
+ }
+
+ public void testShortcutInfoClone_minimum() {
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+ .setId("id")
+ .setTitle("title")
+ .setIntent(makeIntent("action", ShortcutActivity.class))
+ .build();
+ ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals("title", si.getTitle());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals(null, si.getCategories());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals("title", si.getTitle());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals(null, si.getCategories());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals("title", si.getTitle());
+ assertEquals(null, si.getIntent());
+ assertEquals(null, si.getCategories());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(null, si.getTitle());
+ assertEquals(null, si.getIntent());
+ assertEquals(null, si.getCategories());
}
public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
@@ -5102,6 +5164,7 @@
.setIcon(Icon.createWithContentUri("content://a.b.c/"))
.setTitle("title")
.setText("text")
+ .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setExtras(pb)
@@ -5115,38 +5178,57 @@
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setActivityComponent(new ComponentName("x", "y")).build());
+ assertEquals("text", si.getText());
assertEquals(new ComponentName("x", "y"), si.getActivityComponent());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setIcon(Icon.createWithContentUri("content://x.y.z/")).build());
+ assertEquals("text", si.getText());
assertEquals("content://x.y.z/", si.getIcon().getUriString());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setTitle("xyz").build());
+ assertEquals("text", si.getText());
assertEquals("xyz", si.getTitle());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setText("xxx").build());
+ assertEquals(123, si.getWeight());
assertEquals("xxx", si.getText());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setCategories(list()).build());
+ assertEquals("text", si.getText());
+ assertEquals(list(), si.getCategories());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setCategories(list("x")).build());
+ assertEquals("text", si.getText());
+ assertEquals(list("x"), si.getCategories());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setIntent(makeIntent("action2", ShortcutActivity.class)).build());
+ assertEquals("text", si.getText());
assertEquals("action2", si.getIntent().getAction());
assertEquals(null, si.getIntent().getStringExtra("key"));
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
+ assertEquals("text", si.getText());
assertEquals("action3", si.getIntent().getAction());
assertEquals("x", si.getIntent().getStringExtra("key"));
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setWeight(999).build());
+ assertEquals("text", si.getText());
assertEquals(999, si.getWeight());
@@ -5156,8 +5238,11 @@
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setExtras(pb2).build());
+ assertEquals("text", si.getText());
assertEquals(99, si.getExtras().getInt("x"));
+ // Make sure the timestamp gets updated too.
+
final long timestamp = si.getLastChangedTimestamp();
Thread.sleep(2);
@@ -5181,12 +5266,13 @@
.setIcon(bmp32x32)
.setTitle("title")
.setText("text")
+ .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setExtras(pb)
.build();
- mManager.addDynamicShortcut(sorig);
+ mManager.addDynamicShortcuts(list(sorig));
Thread.sleep(2);
final long now = System.currentTimeMillis();
@@ -5207,6 +5293,7 @@
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
@@ -5232,12 +5319,13 @@
.setIcon(bmp32x32)
.setTitle("title")
.setText("text")
+ .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setExtras(pb)
.build();
- mManager.addDynamicShortcut(sorig);
+ mManager.addDynamicShortcuts(list(sorig));
// Dynamic shortcuts won't be backed up, so we need to pin it.
setCaller(LAUNCHER_1, USER_0);
@@ -5246,6 +5334,8 @@
// Do backup & restore.
backupAndRestore();
+ mService.handleUnlockUser(USER_0); // Load user-0.
+
ShortcutInfo si;
si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
@@ -5255,6 +5345,7 @@
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index c00520d..7d404c9 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -90,12 +90,13 @@
}
}
- private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName,
+ private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
WebViewProviderInfo[] webviewPackages) {
- checkCertainPackageUsedAfterWebViewPreparation(expectedProviderName, webviewPackages, 1);
+ checkCertainPackageUsedAfterWebViewBootPreparation(
+ expectedProviderName, webviewPackages, 1);
}
- private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName,
+ private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
WebViewProviderInfo[] webviewPackages, int numRelros) {
setupWithPackages(webviewPackages, true, numRelros);
// Add (enabled and valid) package infos for each provider
@@ -156,6 +157,19 @@
return p;
}
+ private void checkPreparationPhasesForPackage(String expectedPackage, int numPreparation) {
+ // Verify that onWebViewProviderChanged was called for the numPreparation'th time for the
+ // expected package
+ Mockito.verify(mTestSystemImpl, Mockito.times(numPreparation)).onWebViewProviderChanged(
+ Mockito.argThat(new IsPackageInfoWithName(expectedPackage)));
+
+ mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
+
+ WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+ assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
+ assertEquals(expectedPackage, response.packageInfo.packageName);
+ }
+
// ****************
// Tests
@@ -164,7 +178,7 @@
public void testWithSinglePackage() {
String testPackageName = "test.package.name";
- checkCertainPackageUsedAfterWebViewPreparation(testPackageName,
+ checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName,
new WebViewProviderInfo[] {
new WebViewProviderInfo(testPackageName, "",
true /*default available*/, false /* fallback */, null)});
@@ -176,12 +190,12 @@
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
new WebViewProviderInfo(nonDefaultPackage, "", false, false, null),
new WebViewProviderInfo(defaultPackage, "", true, false, null)};
- checkCertainPackageUsedAfterWebViewPreparation(defaultPackage, packages);
+ checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages);
}
public void testSeveralRelros() {
String singlePackage = "singlePackage";
- checkCertainPackageUsedAfterWebViewPreparation(
+ checkCertainPackageUsedAfterWebViewBootPreparation(
singlePackage,
new WebViewProviderInfo[] {
new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)},
@@ -215,14 +229,8 @@
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
- Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
- Mockito.argThat(new IsPackageInfoWithName(validPackage)));
- mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
- WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
- assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
- assertEquals(validPackage, response.packageInfo.packageName);
+ checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */);
WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
assertEquals(1, validPackages.length);
@@ -292,18 +300,10 @@
private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage,
String finalPackage) {
- checkCertainPackageUsedAfterWebViewPreparation(initialPackage, packages);
+ checkCertainPackageUsedAfterWebViewBootPreparation(initialPackage, packages);
mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage);
-
- Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
- Mockito.argThat(new IsPackageInfoWithName(finalPackage)));
-
- mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
- WebViewProviderResponse secondResponse = mWebViewUpdateServiceImpl.waitForAndGetProvider();
- assertEquals(WebViewFactory.LIBLOAD_SUCCESS, secondResponse.status);
- assertEquals(finalPackage, secondResponse.packageInfo.packageName);
+ checkPreparationPhasesForPackage(finalPackage, 1 /* first preparation for this package */);
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage));
}
@@ -455,14 +455,9 @@
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
Matchers.anyObject(), Matchers.anyObject());
- Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
- Mockito.argThat(new IsPackageInfoWithName(fallbackPackage)));
- mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
- WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
- assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
- assertEquals(fallbackPackage, response.packageInfo.packageName);
+ checkPreparationPhasesForPackage(fallbackPackage,
+ 1 /* first preparation for this package*/);
// Install primary package
mTestSystemImpl.setPackageInfo(
@@ -470,17 +465,10 @@
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
WebViewUpdateService.PACKAGE_ADDED);
- // Verify fallback disabled and primary package used as provider
+ // Verify fallback disabled, primary package used as provider, and fallback package killed
Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
Matchers.anyObject(), Mockito.eq(fallbackPackage));
- Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
- Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
-
- // Finish the webview preparation and ensure primary package used and fallback killed
- mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
- response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
- assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
- assertEquals(primaryPackage, response.packageInfo.packageName);
+ checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation for this package*/);
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage));
}
@@ -598,15 +586,72 @@
mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
WebViewUpdateService.PACKAGE_ADDED);
- // Second time we call onWebViewProviderChanged for firstPackage
- Mockito.verify(mTestSystemImpl, Mockito.times(2)).onWebViewProviderChanged(
- Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
+ // Ensure we use firstPackage
+ checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */);
+ }
- mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
+ /**
+ * Verify that even if a user-chosen package is removed temporarily we start using it again when
+ * it is added back.
+ */
+ public void testTempRemovePackageDoesntSwitchProviderPermanently() {
+ String firstPackage = "first";
+ String secondPackage = "second";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(firstPackage, "", true /* default available */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(secondPackage, "", true /* default available */,
+ false /* fallback */, null)};
+ checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
- response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
- assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
- assertEquals(firstPackage, response.packageInfo.packageName);
+ // Explicitly use the second package
+ mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
+ checkPreparationPhasesForPackage(secondPackage, 1 /* first time for this package */);
+
+ // Remove second package (invalidate it) and verify that first package is used
+ mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
+ false /* valid */));
+ mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
+ WebViewUpdateService.PACKAGE_ADDED);
+ checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */);
+
+ // Now make the second package valid again and verify that it is used again
+ mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
+ true /* valid */));
+ mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
+ WebViewUpdateService.PACKAGE_ADDED);
+ checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */);
+ }
+
+ /**
+ * Ensure that we update the user-chosen setting across boots if the chosen package is no
+ * longer installed and valid.
+ */
+ public void testProviderSettingChangedDuringBootIfProviderNotAvailable() {
+ String chosenPackage = "chosenPackage";
+ String nonChosenPackage = "non-chosenPackage";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(chosenPackage, "", true /* default available */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(nonChosenPackage, "", true /* default available */,
+ false /* fallback */, null)};
+
+ setupWithPackages(packages);
+ // Only 'install' nonChosenPackage
+ mTestSystemImpl.setPackageInfo(
+ createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */));
+
+ // Set user-chosen package
+ mTestSystemImpl.updateUserSetting(null, chosenPackage);
+
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+ // Verify that we switch the setting to point to the current package
+ Mockito.verify(mTestSystemImpl).updateUserSetting(
+ Mockito.anyObject(), Mockito.eq(nonChosenPackage));
+ assertEquals(nonChosenPackage, mTestSystemImpl.getUserChosenWebViewProvider(null));
+
+ checkPreparationPhasesForPackage(nonChosenPackage, 1);
}
// TODO (gsennton) add more tests for ensuring killPackageDependents is called / not called
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index adc7c21..c18c13c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -426,6 +426,13 @@
public static final String KEY_CARRIER_METERED_APN_TYPES_STRINGS =
"carrier_metered_apn_types_strings";
+ /**
+ * CDMA carrier ERI (Enhanced Roaming Indicator) file name
+ * @hide
+ */
+ public static final String KEY_CARRIER_ERI_FILE_NAME_STRING =
+ "carrier_eri_file_name_string";
+
/* The following 3 fields are related to carrier visual voicemail. */
/**
@@ -705,6 +712,7 @@
"max_retries=3, 5000, 5000, 5000");
sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
+ sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200);
sDefaults.putStringArray(KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{"default", "mms", "dun", "supl"});
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 865af78..0bca628 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -717,16 +717,11 @@
*/
/** {@hide} */
public String getDeviceSoftwareVersion(int slotId) {
- // FIXME methods taking slot id should not use subscription, instead us Uicc directly
- int[] subId = SubscriptionManager.getSubId(slotId);
- if (subId == null || subId.length == 0) {
- return null;
- }
+ ITelephony telephony = getITelephony();
+ if (telephony == null) return null;
+
try {
- IPhoneSubInfo info = getSubscriberInfo();
- if (info == null)
- return null;
- return info.getDeviceSvnUsingSubId(subId[0], mContext.getOpPackageName());
+ return telephony.getDeviceSoftwareVersionForSlot(slotId, getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -798,12 +793,11 @@
*/
/** {@hide} */
public String getImei(int slotId) {
- int[] subId = SubscriptionManager.getSubId(slotId);
+ ITelephony telephony = getITelephony();
+ if (telephony == null) return null;
+
try {
- IPhoneSubInfo info = getSubscriberInfo();
- if (info == null)
- return null;
- return info.getImeiForSubscriber(subId[0], mContext.getOpPackageName());
+ return telephony.getImeiForSlot(slotId, getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1014,22 +1008,32 @@
} else {
phoneId = SubscriptionManager.getPhoneId(subId);
}
+
+ return getCurrentPhoneTypeForSlot(phoneId);
+ }
+
+ /**
+ * See getCurrentPhoneType.
+ *
+ * @hide
+ */
+ public int getCurrentPhoneTypeForSlot(int slotId) {
try{
ITelephony telephony = getITelephony();
- if (telephony != null && subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- return telephony.getActivePhoneTypeForSubscriber(subId);
+ if (telephony != null) {
+ return telephony.getActivePhoneTypeForSlot(slotId);
} else {
// This can happen when the ITelephony interface is not up yet.
- return getPhoneTypeFromProperty(phoneId);
+ return getPhoneTypeFromProperty(slotId);
}
} catch (RemoteException ex) {
// This shouldn't happen in the normal case, as a backup we
// read from the system property.
- return getPhoneTypeFromProperty(phoneId);
+ return getPhoneTypeFromProperty(slotId);
} catch (NullPointerException ex) {
// This shouldn't happen in the normal case, as a backup we
// read from the system property.
- return getPhoneTypeFromProperty(phoneId);
+ return getPhoneTypeFromProperty(slotId);
}
}
@@ -2555,20 +2559,31 @@
* @param subId whose call state is returned
*/
public int getCallState(int subId) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ return getCallStateForSlot(phoneId);
+ }
+
+ /**
+ * See getCallState.
+ *
+ * @hide
+ */
+ public int getCallStateForSlot(int slotId) {
try {
ITelephony telephony = getITelephony();
if (telephony == null)
return CALL_STATE_IDLE;
- return telephony.getCallStateForSubscriber(subId);
+ return telephony.getCallStateForSlot(slotId);
} catch (RemoteException ex) {
// the phone process is restarting.
return CALL_STATE_IDLE;
} catch (NullPointerException ex) {
// the phone process is restarting.
return CALL_STATE_IDLE;
- }
+ }
}
+
/** Data connection activity: No traffic. */
public static final int DATA_ACTIVITY_NONE = 0x00000000;
/** Data connection activity: Currently receiving IP PPP traffic. */
@@ -3629,22 +3644,6 @@
}
/**
- * Returns the response of SIM Authentication through RIL for the default subscription.
- * Returns null if the Authentication hasn't been successful
- *
- * <p>Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
- *
- * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
- * @param data authentication challenge data
- * @return the response of SIM Authentication, or null if not available
- * @hide
- */
- public String getIccSimChallengeResponse(int appType, String data) {
- return getIccAuthentication(getDefaultSubscription(), appType, AUTHTYPE_EAP_SIM, data);
- }
-
- /**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
* @return array of P-CSCF address
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2727319..b41d361 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -360,9 +360,9 @@
int getCallState();
/**
- * Returns the call state for a subId.
+ * Returns the call state for a slot.
*/
- int getCallStateForSubscriber(int subId);
+ int getCallStateForSlot(int slotId);
int getDataActivity();
int getDataState();
@@ -375,12 +375,12 @@
int getActivePhoneType();
/**
- * Returns the current active phone type as integer for particular subId.
+ * Returns the current active phone type as integer for particular slot.
* Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
* and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
- * @param subId user preferred subId.
+ * @param slotId - slot to query.
*/
- int getActivePhoneTypeForSubscriber(int subId);
+ int getActivePhoneTypeForSlot(int slotId);
/**
* Returns the CDMA ERI icon index to display
@@ -992,6 +992,26 @@
String getDeviceId(String callingPackage);
/**
+ * Returns the IMEI for the given slot.
+ *
+ * @param slotId - device slot.
+ * @param callingPackage The package making the call.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ */
+ String getImeiForSlot(int slotId, String callingPackage);
+
+ /**
+ * Returns the device software version.
+ *
+ * @param slotId - device slot.
+ * @param callingPackage The package making the call.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ */
+ String getDeviceSoftwareVersionForSlot(int slotId, String callingPackage);
+
+ /**
* Returns the subscription ID associated with the specified PhoneAccount.
*/
int getSubIdForPhoneAccount(in PhoneAccount phoneAccount);
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
deleted file mode 100644
index 069fcbf..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.ITelephonyDebugSubscriber;
-
-import android.os.Bundle;
-
-/**
- * Interface used to interact with the Telephony debug service.
- *
- * {@hide}
- */
-interface ITelephonyDebug {
-
- /**
- * Write telephony event
- * @param timestamp returned by System.currentTimeMillis()
- * @param phoneId for which event is written
- * @param tag constant defined in TelephonyEventLog
- * @param param1 optional
- * @param param2 optional
- * @param data optional
- */
- void writeEvent(long timestamp, int phoneId, int tag, int param1, int param2, in Bundle data);
-
- void subscribe(in ITelephonyDebugSubscriber subscriber);
- void unsubscribe(in ITelephonyDebugSubscriber subscriber);
-}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
deleted file mode 100644
index 64eb0f1..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.TelephonyEvent;
-
-import android.os.Bundle;
-
-/**
- * Interface used to subscribe for events from Telephony debug service.
- *
- * {@hide}
- */
-oneway interface ITelephonyDebugSubscriber {
-
- /**
- * Called when Telephony debug service has events.
- */
- void onEvents(in TelephonyEvent[] events);
-}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
deleted file mode 100644
index 1e74b31..0000000
--- a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.telephony;
-
-parcelable TelephonyEvent;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.java b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
deleted file mode 100644
index 26d466d..0000000
--- a/telephony/java/com/android/internal/telephony/TelephonyEvent.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.telephony;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A parcelable used in ITelephonyDebugSubscriber.aidl
- */
-public class TelephonyEvent implements Parcelable {
-
- final public long timestamp;
- final public int phoneId;
- final public int tag;
- final public int param1;
- final public int param2;
- final public Bundle data;
-
- public TelephonyEvent(long timestamp, int phoneId, int tag,
- int param1, int param2, Bundle data) {
- this.timestamp = timestamp;
- this.phoneId = phoneId;
- this.tag = tag;
- this.param1 = param1;
- this.param2 = param2;
- this.data = data;
- }
-
- /** Implement the Parcelable interface */
- public static final Parcelable.Creator<TelephonyEvent> CREATOR
- = new Parcelable.Creator<TelephonyEvent> (){
- public TelephonyEvent createFromParcel(Parcel source) {
- final long timestamp = source.readLong();
- final int phoneId = source.readInt();
- final int tag = source.readInt();
- final int param1 = source.readInt();
- final int param2 = source.readInt();
- final Bundle data = source.readBundle();
- return new TelephonyEvent(timestamp, phoneId, tag, param1, param2, data);
- }
-
- public TelephonyEvent[] newArray(int size) {
- return new TelephonyEvent[size];
- }
- };
-
- /** Implement the Parcelable interface */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeLong(timestamp);
- dest.writeInt(phoneId);
- dest.writeInt(tag);
- dest.writeInt(param1);
- dest.writeInt(param2);
- dest.writeBundle(data);
- }
-
- public String toString() {
- return String.format("%d,%d,%d,%d,%d,%s",
- timestamp, phoneId, tag, param1, param2, data);
- }
-}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 91e891f..2e5ed3f 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -691,6 +691,15 @@
throw new UnsupportedOperationException();
}
+ /**
+ * @hide - to match hiding in superclass
+ */
+ @Override
+ public void deleteApplicationCacheFilesAsUser(String packageName, int userId,
+ IPackageDataObserver observer) {
+ throw new UnsupportedOperationException();
+ }
+
/** {@hide} */
@Override
public void freeStorageAndNotify(String volumeUuid, long idealStorageSize,
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 6c8be39..a4aab7c 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -25,6 +25,7 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
+import android.media.AudioAttributes;
import android.os.Bundle;
import android.os.Vibrator;
import android.os.Handler;
@@ -86,6 +87,28 @@
}
private Test[] mTests = new Test[] {
+ new Test("Phone call") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("phone call")
+ .setLights(0xff0000ff, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"),
+ new AudioAttributes.Builder().setUsage(
+ AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build())
+ .setPriority(Notification.PRIORITY_MAX)
+ .setVibrate(new long[] {
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 })
+ .setFullScreenIntent(makeIntent2(), true)
+ .build();
+ mNM.notify(7001, n);
+ }
+ },
new Test("Post a group") {
public void run()
{
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index 005a483..c1f0038 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -37,6 +37,8 @@
final int parentLeft, parentTop;
final Matrix matrix;
final String className;
+ final float textSize;
+ final int textColor;
final CharSequence text;
final int scrollY;
final int[] lineCharOffsets;
@@ -50,6 +52,8 @@
this.parentTop = parentTop;
this.matrix = new Matrix(matrix);
this.className = node.getClassName();
+ this.textSize = node.getTextSize();
+ this.textColor = node.getTextColor();
this.text = node.getText() != null ? node.getText() : node.getContentDescription();
this.scrollY = node.getScrollY();
this.lineCharOffsets = node.getTextLineCharOffsets();
@@ -113,7 +117,9 @@
TextEntry te = mTextRects.get(i);
Log.d(TAG, "View " + te.className + " " + te.bounds.toShortString()
+ " in " + te.parentLeft + "," + te.parentTop
- + " matrix=" + te.matrix.toShortString() + ": "
+ + " matrix=" + te.matrix.toShortString()
+ + " size=" + te.textSize + " color=#" + Integer.toHexString(te.textColor)
+ + ": "
+ te.text);
if (te.lineCharOffsets != null && te.lineBaselines != null) {
final int num = te.lineCharOffsets.length < te.lineBaselines.length
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index b5ed1b5..81ab3cc 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -1,13 +1,17 @@
#!/usr/bin/env python
import collections
+import copy
import glob
+import itertools
from os import path
import sys
from xml.etree import ElementTree
from fontTools import ttLib
+EMOJI_VS = 0xFE0F
+
LANG_TO_SCRIPT = {
'as': 'Beng',
'bn': 'Beng',
@@ -57,13 +61,26 @@
return LANG_TO_SCRIPT[lang]
-def get_best_cmap(font):
+def printable(inp):
+ if type(inp) is set: # set of character sequences
+ return '{' + ', '.join([printable(seq) for seq in inp]) + '}'
+ if type(inp) is tuple: # character sequence
+ return '<' + (', '.join([printable(ch) for ch in inp])) + '>'
+ else: # single character
+ return 'U+%04X' % inp
+
+
+def open_font(font):
font_file, index = font
font_path = path.join(_fonts_dir, font_file)
if index is not None:
- ttfont = ttLib.TTFont(font_path, fontNumber=index)
+ return ttLib.TTFont(font_path, fontNumber=index)
else:
- ttfont = ttLib.TTFont(font_path)
+ return ttLib.TTFont(font_path)
+
+
+def get_best_cmap(font):
+ ttfont = open_font(font)
all_unicode_cmap = None
bmp_cmap = None
for cmap in ttfont['cmap'].tables:
@@ -79,6 +96,52 @@
return all_unicode_cmap.cmap if all_unicode_cmap else bmp_cmap.cmap
+def get_variation_sequences_cmap(font):
+ ttfont = open_font(font)
+ vs_cmap = None
+ for cmap in ttfont['cmap'].tables:
+ specifier = (cmap.format, cmap.platformID, cmap.platEncID)
+ if specifier == (14, 0, 5):
+ assert vs_cmap is None, 'More than one VS cmap in %s' % (font, )
+ vs_cmap = cmap
+ return vs_cmap
+
+
+def get_emoji_map(font):
+ # Add normal characters
+ emoji_map = copy.copy(get_best_cmap(font))
+ reverse_cmap = {glyph: code for code, glyph in emoji_map.items()}
+
+ # Add variation sequences
+ vs_dict = get_variation_sequences_cmap(font).uvsDict
+ for vs in vs_dict:
+ for base, glyph in vs_dict[vs]:
+ if glyph is None:
+ emoji_map[(base, vs)] = emoji_map[base]
+ else:
+ emoji_map[(base, vs)] = glyph
+
+ # Add GSUB rules
+ ttfont = open_font(font)
+ for lookup in ttfont['GSUB'].table.LookupList.Lookup:
+ assert lookup.LookupType == 4, 'We only understand type 4 lookups'
+ for subtable in lookup.SubTable:
+ ligatures = subtable.ligatures
+ for first_glyph in ligatures:
+ for ligature in ligatures[first_glyph]:
+ sequence = [first_glyph] + ligature.Component
+ sequence = [reverse_cmap[glyph] for glyph in sequence]
+ sequence = tuple(sequence)
+ # Make sure no starting subsequence of 'sequence' has been
+ # seen before.
+ for sub_len in range(2, len(sequence)+1):
+ subsequence = sequence[:sub_len]
+ assert subsequence not in emoji_map
+ emoji_map[sequence] = ligature.LigGlyph
+
+ return emoji_map
+
+
def assert_font_supports_any_of_chars(font, chars):
best_cmap = get_best_cmap(font)
for char in chars:
@@ -101,6 +164,13 @@
'U+%04X was found in %s' % (char, font))
+def assert_font_supports_all_sequences(font, sequences):
+ vs_dict = get_variation_sequences_cmap(font).uvsDict
+ for base, vs in sorted(sequences):
+ assert vs in vs_dict and (base, None) in vs_dict[vs], (
+ '<U+%04X, U+%04X> was not found in %s' % (base, vs, font))
+
+
def check_hyphens(hyphens_dir):
# Find all the scripts that need automatic hyphenation
scripts = set()
@@ -119,6 +189,16 @@
assert_font_supports_any_of_chars(font, HYPHENS)
+class FontRecord(object):
+ def __init__(self, name, scripts, variant, weight, style, font):
+ self.name = name
+ self.scripts = scripts
+ self.variant = variant
+ self.weight = weight
+ self.style = style
+ self.font = font
+
+
def parse_fonts_xml(fonts_xml_path):
global _script_to_font_map, _fallback_chain
_script_to_font_map = collections.defaultdict(set)
@@ -159,7 +239,7 @@
if index:
index = int(index)
- _fallback_chain.append((
+ _fallback_chain.append(FontRecord(
name,
frozenset(scripts),
variant,
@@ -175,39 +255,72 @@
_script_to_font_map[script].add((font_file, index))
-def check_emoji_availability():
- emoji_fonts = [font[5] for font in _fallback_chain if 'Zsye' in font[1]]
+def check_emoji_coverage(all_emoji, equivalent_emoji):
+ emoji_fonts = [
+ record.font for record in _fallback_chain
+ if 'Zsye' in record.scripts]
assert len(emoji_fonts) == 1, 'There are %d emoji fonts.' % len(emoji_fonts)
emoji_font = emoji_fonts[0]
- emoji_chars = _emoji_properties['Emoji']
- assert_font_supports_all_of_chars(emoji_font, emoji_chars)
+ coverage = get_emoji_map(emoji_font)
+
+ for sequence in all_emoji:
+ assert sequence in coverage, (
+ '%s is not supported in the emoji font.' % printable(sequence))
+
+ for sequence in coverage:
+ if sequence in {0x0000, 0x000D, 0x0020}:
+ # The font needs to support a few extra characters, which is OK
+ continue
+ assert sequence in all_emoji, (
+ 'Emoji font should not support %s.' % printable(sequence))
+
+ for first, second in sorted(equivalent_emoji.items()):
+ assert coverage[first] == coverage[second], (
+ '%s and %s should map to the same glyph.' % (
+ printable(first),
+ printable(second)))
+
+ for glyph in set(coverage.values()):
+ maps_to_glyph = [seq for seq in coverage if coverage[seq] == glyph]
+ if len(maps_to_glyph) > 1:
+ # There are more than one sequences mapping to the same glyph. We
+ # need to make sure they were expected to be equivalent.
+ equivalent_seqs = set()
+ for seq in maps_to_glyph:
+ equivalent_seq = seq
+ while equivalent_seq in equivalent_emoji:
+ equivalent_seq = equivalent_emoji[equivalent_seq]
+ equivalent_seqs.add(equivalent_seq)
+ assert len(equivalent_seqs) == 1, (
+ 'The sequences %s should not result in the same glyph %s' % (
+ printable(equivalent_seqs),
+ glyph))
-def check_emoji_defaults():
- default_emoji_chars = _emoji_properties['Emoji_Presentation']
- missing_text_chars = _emoji_properties['Emoji'] - default_emoji_chars
+def check_emoji_defaults(default_emoji):
+ missing_text_chars = _emoji_properties['Emoji'] - default_emoji
emoji_font_seen = False
- for name, scripts, variant, weight, style, font in _fallback_chain:
- if 'Zsye' in scripts:
+ for record in _fallback_chain:
+ if 'Zsye' in record.scripts:
emoji_font_seen = True
# No need to check the emoji font
continue
# For later fonts, we only check them if they have a script
# defined, since the defined script may get them to a higher
# score even if they appear after the emoji font.
- if emoji_font_seen and not scripts:
+ if emoji_font_seen and not record.scripts:
continue
# Check default emoji-style characters
- assert_font_supports_none_of_chars(font, sorted(default_emoji_chars))
+ assert_font_supports_none_of_chars(record.font, sorted(default_emoji))
# Mark default text-style characters appearing in fonts above the emoji
# font as seen
if not emoji_font_seen:
- missing_text_chars -= set(get_best_cmap(font))
+ missing_text_chars -= set(get_best_cmap(record.font))
- # Noto does not have monochrome symbols for Unicode 7.0 wingdings and
- # webdings
+ # Noto does not have monochrome glyphs for Unicode 7.0 wingdings and
+ # webdings yet.
missing_text_chars -= _chars_by_age['7.0']
# TODO: Remove these after b/26113320 is fixed
missing_text_chars -= {
@@ -236,31 +349,175 @@
line = line.strip()
if not line:
continue
- char_range, prop = line.split(';')
- char_range = char_range.strip()
+
+ chars, prop = line.split(';')
+ chars = chars.strip()
prop = prop.strip()
- if '..' in char_range:
- char_start, char_end = char_range.split('..')
- else:
- char_start = char_end = char_range
- char_start = int(char_start, 16)
- char_end = int(char_end, 16)
- char_range = xrange(char_start, char_end+1)
+
+ if ' ' in chars: # character sequence
+ sequence = [int(ch, 16) for ch in chars.split(' ')]
+ additions = [tuple(sequence)]
+ elif '..' in chars: # character range
+ char_start, char_end = chars.split('..')
+ char_start = int(char_start, 16)
+ char_end = int(char_end, 16)
+ additions = xrange(char_start, char_end+1)
+ else: # singe character
+ additions = [int(chars, 16)]
if reverse:
- output_dict[prop].update(char_range)
+ output_dict[prop].update(additions)
else:
- for char in char_range:
- assert char not in output_dict
- output_dict[char] = prop
+ for addition in additions:
+ assert addition not in output_dict
+ output_dict[addition] = prop
return output_dict
+def parse_standardized_variants(file_path):
+ emoji_set = set()
+ text_set = set()
+ with open(file_path) as datafile:
+ for line in datafile:
+ if '#' in line:
+ line = line[:line.index('#')]
+ line = line.strip()
+ if not line:
+ continue
+ sequence, description, _ = line.split(';')
+ sequence = sequence.strip().split(' ')
+ base = int(sequence[0], 16)
+ vs = int(sequence[1], 16)
+ description = description.strip()
+ if description == 'text style':
+ text_set.add((base, vs))
+ elif description == 'emoji style':
+ emoji_set.add((base, vs))
+ return text_set, emoji_set
+
+
def parse_ucd(ucd_path):
global _emoji_properties, _chars_by_age
+ global _text_variation_sequences, _emoji_variation_sequences
+ global _emoji_sequences, _emoji_zwj_sequences
_emoji_properties = parse_unicode_datafile(
path.join(ucd_path, 'emoji-data.txt'), reverse=True)
_chars_by_age = parse_unicode_datafile(
path.join(ucd_path, 'DerivedAge.txt'), reverse=True)
+ sequences = parse_standardized_variants(
+ path.join(ucd_path, 'StandardizedVariants.txt'))
+ _text_variation_sequences, _emoji_variation_sequences = sequences
+ _emoji_sequences = parse_unicode_datafile(
+ path.join(ucd_path, 'emoji-sequences.txt'))
+ _emoji_zwj_sequences = parse_unicode_datafile(
+ path.join(ucd_path, 'emoji-zwj-sequences.txt'))
+
+
+def flag_sequence(territory_code):
+ return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code)
+
+
+UNSUPPORTED_FLAGS = frozenset({
+ flag_sequence('BL'), flag_sequence('BQ'), flag_sequence('DG'),
+ flag_sequence('EA'), flag_sequence('EH'), flag_sequence('FK'),
+ flag_sequence('GF'), flag_sequence('GP'), flag_sequence('GS'),
+ flag_sequence('MF'), flag_sequence('MQ'), flag_sequence('NC'),
+ flag_sequence('PM'), flag_sequence('RE'), flag_sequence('TF'),
+ flag_sequence('WF'), flag_sequence('XK'), flag_sequence('YT'),
+})
+
+EQUIVALENT_FLAGS = {
+ flag_sequence('BV'): flag_sequence('NO'),
+ flag_sequence('CP'): flag_sequence('FR'),
+ flag_sequence('HM'): flag_sequence('AU'),
+ flag_sequence('SJ'): flag_sequence('NO'),
+ flag_sequence('UM'): flag_sequence('US'),
+}
+
+COMBINING_KEYCAP = 0x20E3
+
+LEGACY_ANDROID_EMOJI = {
+ 0xFE4E5: flag_sequence('JP'),
+ 0xFE4E6: flag_sequence('US'),
+ 0xFE4E7: flag_sequence('FR'),
+ 0xFE4E8: flag_sequence('DE'),
+ 0xFE4E9: flag_sequence('IT'),
+ 0xFE4EA: flag_sequence('GB'),
+ 0xFE4EB: flag_sequence('ES'),
+ 0xFE4EC: flag_sequence('RU'),
+ 0xFE4ED: flag_sequence('CN'),
+ 0xFE4EE: flag_sequence('KR'),
+ 0xFE82C: (ord('#'), COMBINING_KEYCAP),
+ 0xFE82E: (ord('1'), COMBINING_KEYCAP),
+ 0xFE82F: (ord('2'), COMBINING_KEYCAP),
+ 0xFE830: (ord('3'), COMBINING_KEYCAP),
+ 0xFE831: (ord('4'), COMBINING_KEYCAP),
+ 0xFE832: (ord('5'), COMBINING_KEYCAP),
+ 0xFE833: (ord('6'), COMBINING_KEYCAP),
+ 0xFE834: (ord('7'), COMBINING_KEYCAP),
+ 0xFE835: (ord('8'), COMBINING_KEYCAP),
+ 0xFE836: (ord('9'), COMBINING_KEYCAP),
+ 0xFE837: (ord('0'), COMBINING_KEYCAP),
+}
+
+ZWJ_IDENTICALS = {
+ # KISS
+ (0x1F469, 0x200D, 0x2764, 0x200D, 0x1F48B, 0x200D, 0x1F468): 0x1F48F,
+ # COUPLE WITH HEART
+ (0x1F469, 0x200D, 0x2764, 0x200D, 0x1F468): 0x1F491,
+ # FAMILY
+ (0x1F468, 0x200D, 0x1F469, 0x200D, 0x1F466): 0x1F46A,
+}
+
+def compute_expected_emoji():
+ equivalent_emoji = {}
+ sequence_pieces = set()
+ all_sequences = set()
+ all_sequences.update(_emoji_variation_sequences)
+
+ for sequence in _emoji_sequences.keys():
+ sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
+ all_sequences.add(sequence)
+ sequence_pieces.update(sequence)
+
+ for sequence in _emoji_zwj_sequences.keys():
+ sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
+ all_sequences.add(sequence)
+ sequence_pieces.update(sequence)
+ # Add reverse of all emoji ZWJ sequences, which are added to the fonts
+ # as a workaround to get the sequences work in RTL text.
+ reversed_seq = tuple(reversed(sequence))
+ all_sequences.add(reversed_seq)
+ equivalent_emoji[reversed_seq] = sequence
+
+ # Add all two-letter flag sequences, as even the unsupported ones should
+ # resolve to a flag tofu.
+ all_letters = [chr(code) for code in range(ord('A'), ord('Z')+1)]
+ all_two_letter_codes = itertools.product(all_letters, repeat=2)
+ all_flags = {flag_sequence(code) for code in all_two_letter_codes}
+ all_sequences.update(all_flags)
+ tofu_flags = UNSUPPORTED_FLAGS | (all_flags - set(_emoji_sequences.keys()))
+
+ all_emoji = (
+ _emoji_properties['Emoji'] |
+ all_sequences |
+ sequence_pieces |
+ set(LEGACY_ANDROID_EMOJI.keys()))
+ default_emoji = (
+ _emoji_properties['Emoji_Presentation'] |
+ all_sequences |
+ set(LEGACY_ANDROID_EMOJI.keys()))
+
+ first_tofu_flag = sorted(tofu_flags)[0]
+ for flag in tofu_flags:
+ if flag != first_tofu_flag:
+ equivalent_emoji[flag] = first_tofu_flag
+ equivalent_emoji.update(EQUIVALENT_FLAGS)
+ equivalent_emoji.update(LEGACY_ANDROID_EMOJI)
+ equivalent_emoji.update(ZWJ_IDENTICALS)
+ for seq in _emoji_variation_sequences:
+ equivalent_emoji[seq] = seq[0]
+
+ return all_emoji, default_emoji, equivalent_emoji
def main():
@@ -278,8 +535,9 @@
if check_emoji == 'true':
ucd_path = sys.argv[3]
parse_ucd(ucd_path)
- check_emoji_availability()
- check_emoji_defaults()
+ all_emoji, default_emoji, equivalent_emoji = compute_expected_emoji()
+ check_emoji_coverage(all_emoji, equivalent_emoji)
+ check_emoji_defaults(default_emoji)
if __name__ == '__main__':
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
index d8ff57b..7fa7235 100644
--- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -90,7 +90,7 @@
}
@LayoutlibDelegate
- static long nCreateRenderer(long rootGroupPtr) {
+ static long nCreateTree(long rootGroupPtr) {
VGroup_Delegate rootGroup = VNativeObject.getDelegate(rootGroupPtr);
return sPathManager.addNewDelegate(new VPathRenderer_Delegate(rootGroup));
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 9e50ee8..3b88290 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -537,7 +537,7 @@
* Note that while this can be called several time, the first call to {@link #cleanupThread()}
* will do the clean-up, and make the thread unable to do further scene actions.
*/
- public static void prepareThread() {
+ public synchronized static void prepareThread() {
// we need to make sure the Looper has been initialized for this thread.
// this is required for View that creates Handler objects.
if (Looper.myLooper() == null) {
@@ -551,7 +551,7 @@
* Note that it doesn't matter how many times {@link #prepareThread()} was called, a single
* call to this will prevent the thread from doing further scene actions
*/
- public static void cleanupThread() {
+ public synchronized static void cleanupThread() {
// clean up the looper
Looper_Accessor.cleanupThread();
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index fea633e..308488a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -70,23 +70,6 @@
}
@Override
- public Map<String, String> getDefaultProperties(Object viewObject) {
- return mSession.getDefaultProperties(viewObject);
- }
-
- @Override
- public Result getProperty(Object objectView, String propertyName) {
- // pass
- return super.getProperty(objectView, propertyName);
- }
-
- @Override
- public Result setProperty(Object objectView, String propertyName, String propertyValue) {
- // pass
- return super.setProperty(objectView, propertyName, propertyValue);
- }
-
- @Override
public Result render(long timeout, boolean forceMeasure) {
try {
Bridge.prepareThread();
@@ -213,6 +196,10 @@
}
}
+ public RenderSessionImpl getSessionImpl() {
+ return mSession;
+ }
+
/*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
mSession = scene;
if (scene != null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 89272fa..fd95bd5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -27,6 +27,7 @@
import com.android.ide.common.rendering.api.StyleResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.android.PropertiesMap.Property;
import com.android.layoutlib.bridge.android.view.WindowManagerImpl;
import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.impl.Stack;
@@ -275,7 +276,7 @@
return mRenderResources;
}
- public Map<String, String> getDefaultPropMap(Object key) {
+ public PropertiesMap getDefaultPropMap(Object key) {
return mDefaultPropMaps.get(key);
}
@@ -731,16 +732,10 @@
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
"Failed to find the style corresponding to the id " + defStyleAttr, null);
} else {
- if (defaultPropMap != null) {
- String defStyleName = defStyleAttribute.getFirst();
- if (defStyleAttribute.getSecond()) {
- defStyleName = "android:" + defStyleName;
- }
- defaultPropMap.put("style", defStyleName);
- }
+ String defStyleName = defStyleAttribute.getFirst();
// look for the style in the current theme, and its parent:
- ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute.getFirst(),
+ ResourceValue item = mRenderResources.findItemInTheme(defStyleName,
defStyleAttribute.getSecond());
if (item != null) {
@@ -750,6 +745,12 @@
if (item instanceof StyleResourceValue) {
defStyleValues = (StyleResourceValue) item;
}
+ if (defaultPropMap != null) {
+ if (defStyleAttribute.getSecond()) {
+ defStyleName = "android:" + defStyleName;
+ }
+ defaultPropMap.put("style", new Property(defStyleName, item.getValue()));
+ }
} else {
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
String.format(
@@ -776,7 +777,8 @@
item = mRenderResources.getStyle(value.getSecond(), isFrameworkRes);
if (item != null) {
if (defaultPropMap != null) {
- defaultPropMap.put("style", item.getName());
+ String name = item.getName();
+ defaultPropMap.put("style", new Property(name, name));
}
defStyleValues = item;
@@ -855,13 +857,14 @@
// if we found a value, we make sure this doesn't reference another value.
// So we resolve it.
if (resValue != null) {
- // put the first default value, before the resolution.
- if (defaultPropMap != null) {
- defaultPropMap.put(attrName, resValue.getValue());
- }
-
+ String preResolve = resValue.getValue();
resValue = mRenderResources.resolveResValue(resValue);
+ if (defaultPropMap != null) {
+ defaultPropMap.put(attrName,
+ new Property(preResolve, resValue.getValue()));
+ }
+
// If the value is a reference to another theme attribute that doesn't
// exist, we should log a warning and omit it.
String val = resValue.getValue();
@@ -949,10 +952,11 @@
if (resValue != null) {
// Add it to defaultPropMap before resolving
- defaultPropMap.put(attrName, resValue.getValue());
+ String preResolve = resValue.getValue();
// resolve it to make sure there are no references left.
- ta.bridgeSetValue(i, attrName, attribute.getSecond(),
- mRenderResources.resolveResValue(resValue));
+ resValue = mRenderResources.resolveResValue(resValue);
+ ta.bridgeSetValue(i, attrName, attribute.getSecond(), resValue);
+ defaultPropMap.put(attrName, new Property(preResolve, resValue.getValue()));
}
}
}
@@ -1915,11 +1919,4 @@
}
}
-
- /**
- * An alias used for the value in {@code {@link #mDefaultPropMaps}}
- */
- private static class PropertiesMap extends HashMap<String, String> {
- }
-
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 42c0ae0..0a64b63 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -645,6 +645,11 @@
}
@Override
+ public void deleteApplicationCacheFilesAsUser(String packageName, int userId,
+ IPackageDataObserver observer) {
+ }
+
+ @Override
public void freeStorageAndNotify(String volumeUuid, long freeStorageSize,
IPackageDataObserver observer) {
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java
new file mode 100644
index 0000000..a38d579
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package com.android.layoutlib.bridge.android;
+
+import com.android.layoutlib.bridge.android.PropertiesMap.Property;
+
+import java.util.HashMap;
+
+/**
+ * An alias used for the value in {@link BridgeContext#mDefaultPropMaps}
+ */
+public class PropertiesMap extends HashMap<String, Property> {
+
+ public static class Property {
+ public final String resource;
+ public final String value;
+
+ public Property(String resource, String value) {
+ this.resource = resource;
+ this.value = value;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 0c53753..2d38831 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -286,7 +286,7 @@
return mParams;
}
- protected BridgeContext getContext() {
+ public BridgeContext getContext() {
return mContext;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 866b248..11fabc6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -1415,10 +1415,6 @@
return mSystemViewInfoList;
}
- public Map<String, String> getDefaultProperties(Object viewObject) {
- return getContext().getDefaultPropMap(viewObject);
- }
-
public void setScene(RenderSession session) {
mScene = session;
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index fb2bdd4..b8ef150 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1636,6 +1636,9 @@
if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP];
}
+ if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
+ keyMgmt = KeyMgmt.strings[KeyMgmt.OSEN];
+ }
if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 394934f..b614a86 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -437,6 +437,7 @@
switch (eapMethod) {
/** Valid methods */
case Eap.TLS:
+ case Eap.UNAUTH_TLS:
setPhase2Method(Phase2.NONE);
/* fall through */
case Eap.PEAP:
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index f8c1ea3..1a8197c 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -687,7 +687,7 @@
Bundle scanParams = new Bundle();
scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
- sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
+ mAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
}
/**
@@ -700,7 +700,7 @@
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
+ mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
}
/**
* reports currently available scan results on appropriate listeners
@@ -708,7 +708,7 @@
*/
public boolean getScanResults() {
validateChannel();
- Message reply = sAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
+ Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
return reply.what == CMD_OP_SUCCEEDED;
}
@@ -741,7 +741,7 @@
Bundle scanParams = new Bundle();
scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
- sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
+ mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
}
/**
@@ -754,7 +754,7 @@
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
+ mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
}
private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
@@ -764,7 +764,7 @@
scanSettings.isPnoScan = true;
pnoParams.putParcelable(PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
pnoParams.putParcelable(PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings);
- sAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
+ mAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
}
/**
* Start wifi connected PNO scan
@@ -820,7 +820,7 @@
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key);
+ mAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key);
}
/** specifies information about an access point of interest */
@@ -956,7 +956,7 @@
int key = addListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
+ mAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
}
/**
@@ -968,14 +968,14 @@
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
+ mAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
}
/** @hide */
@SystemApi
public void configureWifiChange(WifiChangeSettings settings) {
validateChannel();
- sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+ mAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
}
/** interface to receive hotlist events on; use this on {@link #setHotlist} */
@@ -1060,7 +1060,7 @@
HotlistSettings settings = new HotlistSettings();
settings.bssidInfos = bssidInfos;
settings.apLostThreshold = apLostThreshold;
- sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
+ mAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
}
/**
@@ -1072,7 +1072,7 @@
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
+ mAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
}
@@ -1137,17 +1137,14 @@
private IWifiScanner mService;
private static final int INVALID_KEY = 0;
- private static int sListenerKey = 1;
+ private int mListenerKey = 1;
- private static final SparseArray sListenerMap = new SparseArray();
- private static final Object sListenerMapLock = new Object();
+ private final SparseArray mListenerMap = new SparseArray();
+ private final Object mListenerMapLock = new Object();
- private static AsyncChannel sAsyncChannel;
- private static CountDownLatch sConnected;
-
- private static final Object sThreadRefLock = new Object();
- private static int sThreadRefCount;
- private static Handler sInternalHandler;
+ private AsyncChannel mAsyncChannel;
+ private final CountDownLatch mConnected;
+ private final Handler mInternalHandler;
/**
* Create a new WifiScanner instance.
@@ -1156,10 +1153,11 @@
* the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
* @param context the application context
* @param service the Binder interface
+ * @param looper the Looper used to deliver callbacks
* @hide
*/
- public WifiScanner(Context context, IWifiScanner service) {
- this(context, service, null, true);
+ public WifiScanner(Context context, IWifiScanner service, Looper looper) {
+ this(context, service, looper, true);
}
/**
@@ -1167,8 +1165,7 @@
*
* @param context The application context.
* @param service The IWifiScanner Binder interface
- * @param looper Looper for running WifiScanner operations. If null, a handler thread will be
- * created for running WifiScanner operations.
+ * @param looper the Looper used to deliver callbacks
* @param waitForConnection If true, this will not return until a connection to Wifi Scanner
* service is established.
* @hide
@@ -1178,50 +1175,34 @@
boolean waitForConnection) {
mContext = context;
mService = service;
- init(looper, waitForConnection);
- }
- private void init(Looper looper, boolean waitForConnection) {
- synchronized (sThreadRefLock) {
- if (++sThreadRefCount == 1) {
- Messenger messenger = null;
- try {
- messenger = mService.getMessenger();
- } catch (RemoteException e) {
- /* do nothing */
- } catch (SecurityException e) {
- /* do nothing */
- }
+ Messenger messenger = null;
+ try {
+ messenger = mService.getMessenger();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
- if (messenger == null) {
- sAsyncChannel = null;
- return;
- }
+ if (messenger == null) {
+ throw new IllegalStateException("getMessenger() returned null! This is invalid.");
+ }
- sAsyncChannel = new AsyncChannel();
- sConnected = new CountDownLatch(1);
+ mAsyncChannel = new AsyncChannel();
+ mConnected = new CountDownLatch(1);
- if (looper == null) {
- HandlerThread thread = new HandlerThread("WifiScanner");
- thread.start();
- sInternalHandler = new ServiceHandler(thread.getLooper());
- } else {
- sInternalHandler = new ServiceHandler(looper);
- }
- sAsyncChannel.connect(mContext, sInternalHandler, messenger);
- if (waitForConnection) {
- try {
- sConnected.await();
- } catch (InterruptedException e) {
- Log.e(TAG, "interrupted wait at init");
- }
- }
+ mInternalHandler = new ServiceHandler(looper);
+ mAsyncChannel.connect(mContext, mInternalHandler, messenger);
+ if (waitForConnection) {
+ try {
+ mConnected.await();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "interrupted wait at init");
}
}
}
private void validateChannel() {
- if (sAsyncChannel == null) throw new IllegalStateException(
+ if (mAsyncChannel == null) throw new IllegalStateException(
"No permission to access and change wifi or a bad initialization");
}
@@ -1229,7 +1210,7 @@
// send an error message to internal handler; Otherwise add the listener to the listener map and
// return the key of the listener.
private int addListener(ActionListener listener) {
- synchronized (sListenerMap) {
+ synchronized (mListenerMapLock) {
boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
// Note we need to put the listener into listener map even if it's a duplicate as the
// internal handler will need the key to find the listener. In case of duplicates,
@@ -1239,7 +1220,7 @@
if (DBG) Log.d(TAG, "listener key already exists");
OperationResult operationResult = new OperationResult(REASON_DUPLICATE_REQEUST,
"Outstanding request with same key not stopped yet");
- Message message = Message.obtain(sInternalHandler, CMD_OP_FAILED, 0, key,
+ Message message = Message.obtain(mInternalHandler, CMD_OP_FAILED, 0, key,
operationResult);
message.sendToTarget();
return INVALID_KEY;
@@ -1249,55 +1230,55 @@
}
}
- private static int putListener(Object listener) {
+ private int putListener(Object listener) {
if (listener == null) return INVALID_KEY;
int key;
- synchronized (sListenerMapLock) {
+ synchronized (mListenerMapLock) {
do {
- key = sListenerKey++;
+ key = mListenerKey++;
} while (key == INVALID_KEY);
- sListenerMap.put(key, listener);
+ mListenerMap.put(key, listener);
}
return key;
}
- private static Object getListener(int key) {
+ private Object getListener(int key) {
if (key == INVALID_KEY) return null;
- synchronized (sListenerMapLock) {
- Object listener = sListenerMap.get(key);
+ synchronized (mListenerMapLock) {
+ Object listener = mListenerMap.get(key);
return listener;
}
}
- private static int getListenerKey(Object listener) {
+ private int getListenerKey(Object listener) {
if (listener == null) return INVALID_KEY;
- synchronized (sListenerMapLock) {
- int index = sListenerMap.indexOfValue(listener);
+ synchronized (mListenerMapLock) {
+ int index = mListenerMap.indexOfValue(listener);
if (index == -1) {
return INVALID_KEY;
} else {
- return sListenerMap.keyAt(index);
+ return mListenerMap.keyAt(index);
}
}
}
- private static Object removeListener(int key) {
+ private Object removeListener(int key) {
if (key == INVALID_KEY) return null;
- synchronized (sListenerMapLock) {
- Object listener = sListenerMap.get(key);
- sListenerMap.remove(key);
+ synchronized (mListenerMapLock) {
+ Object listener = mListenerMap.get(key);
+ mListenerMap.remove(key);
return listener;
}
}
- private static int removeListener(Object listener) {
+ private int removeListener(Object listener) {
int key = getListenerKey(listener);
if (key == INVALID_KEY) {
Log.e(TAG, "listener cannot be found");
return key;
}
- synchronized (sListenerMapLock) {
- sListenerMap.remove(key);
+ synchronized (mListenerMapLock) {
+ mListenerMap.remove(key);
return key;
}
}
@@ -1338,7 +1319,7 @@
};
}
- private static class ServiceHandler extends Handler {
+ private class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
}
@@ -1347,14 +1328,14 @@
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
} else {
Log.e(TAG, "Failed to set up channel connection");
// This will cause all further async API calls on the WifiManager
// to fail and throw an exception
- sAsyncChannel = null;
+ mAsyncChannel = null;
}
- sConnected.countDown();
+ mConnected.countDown();
return;
case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
return;
@@ -1362,7 +1343,7 @@
Log.e(TAG, "Channel connection lost");
// This will cause all further async API calls on the WifiManager
// to fail and throw an exception
- sAsyncChannel = null;
+ mAsyncChannel = null;
getLooper().quit();
return;
}