diff options
279 files changed, 4252 insertions, 2197 deletions
diff --git a/api/current.txt b/api/current.txt index baedbeb8002b..418940918654 100644 --- a/api/current.txt +++ b/api/current.txt @@ -334,6 +334,7 @@ package android { field public static final int calendarViewShown = 16843596; // 0x101034c field public static final int calendarViewStyle = 16843613; // 0x101035d field public static final int canControlMagnification = 16844040; // 0x1010508 + field public static final int canPerformGestures = 16844046; // 0x101050e field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8 field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9 field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7 @@ -2610,6 +2611,7 @@ package android.accessibilityservice { public abstract class AccessibilityService extends android.app.Service { ctor public AccessibilityService(); + method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController(); method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow(); @@ -2649,6 +2651,12 @@ package android.accessibilityservice { field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice"; } + public static abstract class AccessibilityService.GestureResultCallback { + ctor public AccessibilityService.GestureResultCallback(); + method public void onCancelled(android.accessibilityservice.GestureDescription); + method public void onCompleted(android.accessibilityservice.GestureDescription); + } + public static final class AccessibilityService.MagnificationController { method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener); method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler); @@ -2681,6 +2689,7 @@ package android.accessibilityservice { method public java.lang.String loadDescription(android.content.pm.PackageManager); method public void writeToParcel(android.os.Parcel, int); field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10 + field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20 field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4 field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8 field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2 @@ -2707,6 +2716,30 @@ package android.accessibilityservice { field public java.lang.String[] packageNames; } + public final class GestureDescription { + method public static android.accessibilityservice.GestureDescription createClick(int, int); + method public static android.accessibilityservice.GestureDescription createLongClick(int, int); + method public static android.accessibilityservice.GestureDescription createPinch(int, int, int, int, float, long); + method public static android.accessibilityservice.GestureDescription createSwipe(int, int, int, int, long); + method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(int); + method public int getStrokeCount(); + field public static final long MAX_GESTURE_DURATION_MS = 60000L; // 0xea60L + field public static final int MAX_STROKE_COUNT = 10; // 0xa + } + + public static class GestureDescription.Builder { + ctor public GestureDescription.Builder(); + method public android.accessibilityservice.GestureDescription.Builder addStroke(android.accessibilityservice.GestureDescription.StrokeDescription); + method public android.accessibilityservice.GestureDescription build(); + } + + public static class GestureDescription.StrokeDescription { + ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long); + method public long getDuration(); + method public android.graphics.Path getPath(); + method public long getStartTime(); + } + } package android.accounts { @@ -6133,6 +6166,7 @@ package android.app.job { method public int describeContents(); method public int getBackoffPolicy(); method public android.os.PersistableBundle getExtras(); + method public long getFlexMillis(); method public int getId(); method public long getInitialBackoffMillis(); method public long getIntervalMillis(); @@ -6150,6 +6184,8 @@ package android.app.job { field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR; field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L + field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L + field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L field public static final int NETWORK_TYPE_ANY = 1; // 0x1 field public static final int NETWORK_TYPE_NONE = 0; // 0x0 field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2 @@ -6163,6 +6199,7 @@ package android.app.job { method public android.app.job.JobInfo.Builder setMinimumLatency(long); method public android.app.job.JobInfo.Builder setOverrideDeadline(long); method public android.app.job.JobInfo.Builder setPeriodic(long); + method public android.app.job.JobInfo.Builder setPeriodic(long, long); method public android.app.job.JobInfo.Builder setPersisted(boolean); method public android.app.job.JobInfo.Builder setRequiredNetworkType(int); method public android.app.job.JobInfo.Builder setRequiresCharging(boolean); @@ -6223,6 +6260,8 @@ package android.app.usage { public static class NetworkStats.Bucket { ctor public NetworkStats.Bucket(); method public long getEndTimeStamp(); + method public int getMetering(); + method public int getRoaming(); method public long getRxBytes(); method public long getRxPackets(); method public long getStartTimeStamp(); @@ -6230,6 +6269,12 @@ package android.app.usage { method public long getTxBytes(); method public long getTxPackets(); method public int getUid(); + field public static final int METERING_ALL = -1; // 0xffffffff + field public static final int METERING_DEFAULT = 1; // 0x1 + field public static final int METERING_METERED = 2; // 0x2 + field public static final int ROAMING_ALL = -1; // 0xffffffff + field public static final int ROAMING_DEFAULT = 1; // 0x1 + field public static final int ROAMING_ROAMING = 2; // 0x2 field public static final int STATE_ALL = -1; // 0xffffffff field public static final int STATE_DEFAULT = 1; // 0x1 field public static final int STATE_FOREGROUND = 2; // 0x2 @@ -9443,8 +9488,6 @@ package android.content.pm { method public abstract int getComponentEnabledSetting(android.content.ComponentName); method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon(); method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); - method public abstract byte[] getEphemeralCookie(); - method public abstract int getEphemeralCookieMaxSizeBytes(); method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int); method public abstract java.lang.String getInstallerPackageName(java.lang.String); @@ -9478,7 +9521,6 @@ package android.content.pm { method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle); method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract boolean hasSystemFeature(java.lang.String); - method public abstract boolean isEphemeralApplication(); method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public abstract boolean isSafeMode(); method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); @@ -9496,7 +9538,6 @@ package android.content.pm { method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int); method public abstract void setApplicationEnabledSetting(java.lang.String, int, int); method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int); - method public abstract boolean setEphemeralCookie(byte[]); method public abstract void setInstallerPackageName(java.lang.String, java.lang.String); method public abstract void verifyPendingInstall(int, int); field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0 @@ -27198,7 +27239,7 @@ package android.opengl { ctor public GLException(int, java.lang.String); } - public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback { + public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback2 { ctor public GLSurfaceView(android.content.Context); ctor public GLSurfaceView(android.content.Context, android.util.AttributeSet); method public int getDebugFlags(); @@ -27222,6 +27263,7 @@ package android.opengl { method public void surfaceChanged(android.view.SurfaceHolder, int, int, int); method public void surfaceCreated(android.view.SurfaceHolder); method public void surfaceDestroyed(android.view.SurfaceHolder); + method public void surfaceRedrawNeeded(android.view.SurfaceHolder); field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1 field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2 field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1 @@ -31336,6 +31378,7 @@ package android.provider { field public static final java.lang.String AUTO_TIME = "auto_time"; field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone"; field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on"; + field public static final java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync"; field public static final android.net.Uri CONTENT_URI; field public static final java.lang.String DATA_ROAMING = "data_roaming"; field public static final java.lang.String DEBUG_APP = "debug_app"; @@ -33578,6 +33621,7 @@ package android.service.notification { field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 + field public static final int REASON_TOPIC_BANNED = 14; // 0xe field public static final int REASON_USER_STOPPED = 6; // 0x6 field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } @@ -36802,8 +36846,6 @@ package android.test.mock { method public int getComponentEnabledSetting(android.content.ComponentName); method public android.graphics.drawable.Drawable getDefaultActivityIcon(); method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); - method public byte[] getEphemeralCookie(); - method public int getEphemeralCookieMaxSizeBytes(); method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int); method public java.lang.String getInstallerPackageName(java.lang.String); @@ -36836,7 +36878,6 @@ package android.test.mock { method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle); method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public boolean hasSystemFeature(java.lang.String); - method public boolean isEphemeralApplication(); method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public boolean isSafeMode(); method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); @@ -36854,7 +36895,6 @@ package android.test.mock { method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int); method public void setApplicationEnabledSetting(java.lang.String, int, int); method public void setComponentEnabledSetting(android.content.ComponentName, int, int); - method public boolean setEphemeralCookie(byte[]); method public void setInstallerPackageName(java.lang.String, java.lang.String); method public void verifyPendingInstall(int, int); } @@ -39085,7 +39125,9 @@ package android.util { method public static android.util.LocaleList getEmptyLocaleList(); method public java.util.Locale getFirstMatch(java.lang.String[]); method public java.util.Locale getPrimary(); + method public int indexOf(java.util.Locale); method public boolean isEmpty(); + method public static void setDefault(android.util.LocaleList); method public int size(); method public java.lang.String toLanguageTags(); method public void writeToParcel(android.os.Parcel, int); diff --git a/api/system-current.txt b/api/system-current.txt index 4c3efabbae53..35f42148ee61 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -214,6 +214,7 @@ package android { 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 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"; field public static final java.lang.String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE"; field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT"; @@ -428,6 +429,7 @@ package android { field public static final int calendarViewShown = 16843596; // 0x101034c field public static final int calendarViewStyle = 16843613; // 0x101035d field public static final int canControlMagnification = 16844040; // 0x1010508 + field public static final int canPerformGestures = 16844046; // 0x101050e field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8 field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9 field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7 @@ -2711,6 +2713,7 @@ package android.accessibilityservice { public abstract class AccessibilityService extends android.app.Service { ctor public AccessibilityService(); + method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController(); method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow(); @@ -2750,6 +2753,12 @@ package android.accessibilityservice { field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice"; } + public static abstract class AccessibilityService.GestureResultCallback { + ctor public AccessibilityService.GestureResultCallback(); + method public void onCancelled(android.accessibilityservice.GestureDescription); + method public void onCompleted(android.accessibilityservice.GestureDescription); + } + public static final class AccessibilityService.MagnificationController { method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener); method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler); @@ -2782,6 +2791,7 @@ package android.accessibilityservice { method public java.lang.String loadDescription(android.content.pm.PackageManager); method public void writeToParcel(android.os.Parcel, int); field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10 + field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20 field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4 field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8 field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2 @@ -2808,6 +2818,30 @@ package android.accessibilityservice { field public java.lang.String[] packageNames; } + public final class GestureDescription { + method public static android.accessibilityservice.GestureDescription createClick(int, int); + method public static android.accessibilityservice.GestureDescription createLongClick(int, int); + method public static android.accessibilityservice.GestureDescription createPinch(int, int, int, int, float, long); + method public static android.accessibilityservice.GestureDescription createSwipe(int, int, int, int, long); + method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(int); + method public int getStrokeCount(); + field public static final long MAX_GESTURE_DURATION_MS = 60000L; // 0xea60L + field public static final int MAX_STROKE_COUNT = 10; // 0xa + } + + public static class GestureDescription.Builder { + ctor public GestureDescription.Builder(); + method public android.accessibilityservice.GestureDescription.Builder addStroke(android.accessibilityservice.GestureDescription.StrokeDescription); + method public android.accessibilityservice.GestureDescription build(); + } + + public static class GestureDescription.StrokeDescription { + ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long); + method public long getDuration(); + method public android.graphics.Path getPath(); + method public long getStartTime(); + } + } package android.accounts { @@ -6347,6 +6381,7 @@ package android.app.job { method public int describeContents(); method public int getBackoffPolicy(); method public android.os.PersistableBundle getExtras(); + method public long getFlexMillis(); method public int getId(); method public long getInitialBackoffMillis(); method public long getIntervalMillis(); @@ -6364,6 +6399,8 @@ package android.app.job { field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR; field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L + field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L + field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L field public static final int NETWORK_TYPE_ANY = 1; // 0x1 field public static final int NETWORK_TYPE_NONE = 0; // 0x0 field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2 @@ -6377,6 +6414,7 @@ package android.app.job { method public android.app.job.JobInfo.Builder setMinimumLatency(long); method public android.app.job.JobInfo.Builder setOverrideDeadline(long); method public android.app.job.JobInfo.Builder setPeriodic(long); + method public android.app.job.JobInfo.Builder setPeriodic(long, long); method public android.app.job.JobInfo.Builder setPersisted(boolean); method public android.app.job.JobInfo.Builder setRequiredNetworkType(int); method public android.app.job.JobInfo.Builder setRequiresCharging(boolean); @@ -6437,6 +6475,8 @@ package android.app.usage { public static class NetworkStats.Bucket { ctor public NetworkStats.Bucket(); method public long getEndTimeStamp(); + method public int getMetering(); + method public int getRoaming(); method public long getRxBytes(); method public long getRxPackets(); method public long getStartTimeStamp(); @@ -6444,6 +6484,12 @@ package android.app.usage { method public long getTxBytes(); method public long getTxPackets(); method public int getUid(); + field public static final int METERING_ALL = -1; // 0xffffffff + field public static final int METERING_DEFAULT = 1; // 0x1 + field public static final int METERING_METERED = 2; // 0x2 + field public static final int ROAMING_ALL = -1; // 0xffffffff + field public static final int ROAMING_DEFAULT = 1; // 0x1 + field public static final int ROAMING_ROAMING = 2; // 0x2 field public static final int STATE_ALL = -1; // 0xffffffff field public static final int STATE_DEFAULT = 1; // 0x1 field public static final int STATE_FOREGROUND = 2; // 0x2 @@ -9744,8 +9790,6 @@ package android.content.pm { method public abstract int getComponentEnabledSetting(android.content.ComponentName); method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon(); method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); - method public abstract byte[] getEphemeralCookie(); - method public abstract int getEphemeralCookieMaxSizeBytes(); method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int); method public abstract java.lang.String getInstallerPackageName(java.lang.String); @@ -9781,7 +9825,6 @@ package android.content.pm { method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public abstract boolean hasSystemFeature(java.lang.String); - method public abstract boolean isEphemeralApplication(); method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public abstract boolean isSafeMode(); method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); @@ -9801,7 +9844,6 @@ package android.content.pm { method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public abstract void setApplicationEnabledSetting(java.lang.String, int, int); method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int); - method public abstract boolean setEphemeralCookie(byte[]); method public abstract void setInstallerPackageName(java.lang.String, java.lang.String); method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle); method public abstract void verifyIntentFilter(int, int, java.util.List<java.lang.String>); @@ -29188,7 +29230,7 @@ package android.opengl { ctor public GLException(int, java.lang.String); } - public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback { + public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback2 { ctor public GLSurfaceView(android.content.Context); ctor public GLSurfaceView(android.content.Context, android.util.AttributeSet); method public int getDebugFlags(); @@ -29212,6 +29254,7 @@ package android.opengl { method public void surfaceChanged(android.view.SurfaceHolder, int, int, int); method public void surfaceCreated(android.view.SurfaceHolder); method public void surfaceDestroyed(android.view.SurfaceHolder); + method public void surfaceRedrawNeeded(android.view.SurfaceHolder); field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1 field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2 field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1 @@ -33471,6 +33514,7 @@ package android.provider { field public static final java.lang.String AUTO_TIME = "auto_time"; field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone"; field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on"; + field public static final java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync"; field public static final android.net.Uri CONTENT_URI; field public static final java.lang.String DATA_ROAMING = "data_roaming"; field public static final java.lang.String DEBUG_APP = "debug_app"; @@ -35714,6 +35758,7 @@ package android.service.notification { field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 + field public static final int REASON_TOPIC_BANNED = 14; // 0xe field public static final int REASON_USER_STOPPED = 6; // 0x6 field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } @@ -39144,8 +39189,6 @@ package android.test.mock { method public int getComponentEnabledSetting(android.content.ComponentName); method public android.graphics.drawable.Drawable getDefaultActivityIcon(); method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); - method public byte[] getEphemeralCookie(); - method public int getEphemeralCookieMaxSizeBytes(); method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int); method public java.lang.String getInstallerPackageName(java.lang.String); @@ -39180,7 +39223,6 @@ package android.test.mock { method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public boolean hasSystemFeature(java.lang.String); - method public boolean isEphemeralApplication(); method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public boolean isSafeMode(); method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); @@ -39200,7 +39242,6 @@ package android.test.mock { method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public void setApplicationEnabledSetting(java.lang.String, int, int); method public void setComponentEnabledSetting(android.content.ComponentName, int, int); - method public boolean setEphemeralCookie(byte[]); method public void setInstallerPackageName(java.lang.String, java.lang.String); method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle); method public void verifyIntentFilter(int, int, java.util.List<java.lang.String>); @@ -41433,7 +41474,9 @@ package android.util { method public static android.util.LocaleList getEmptyLocaleList(); method public java.util.Locale getFirstMatch(java.lang.String[]); method public java.util.Locale getPrimary(); + method public int indexOf(java.util.Locale); method public boolean isEmpty(); + method public static void setDefault(android.util.LocaleList); method public int size(); method public java.lang.String toLanguageTags(); method public void writeToParcel(android.os.Parcel, int); diff --git a/api/test-current.txt b/api/test-current.txt index daecc2bce215..f15ab581877b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -334,6 +334,7 @@ package android { field public static final int calendarViewShown = 16843596; // 0x101034c field public static final int calendarViewStyle = 16843613; // 0x101035d field public static final int canControlMagnification = 16844040; // 0x1010508 + field public static final int canPerformGestures = 16844046; // 0x101050e field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8 field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9 field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7 @@ -2610,6 +2611,7 @@ package android.accessibilityservice { public abstract class AccessibilityService extends android.app.Service { ctor public AccessibilityService(); + method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController(); method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow(); @@ -2649,6 +2651,12 @@ package android.accessibilityservice { field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice"; } + public static abstract class AccessibilityService.GestureResultCallback { + ctor public AccessibilityService.GestureResultCallback(); + method public void onCancelled(android.accessibilityservice.GestureDescription); + method public void onCompleted(android.accessibilityservice.GestureDescription); + } + public static final class AccessibilityService.MagnificationController { method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener); method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler); @@ -2681,6 +2689,7 @@ package android.accessibilityservice { method public java.lang.String loadDescription(android.content.pm.PackageManager); method public void writeToParcel(android.os.Parcel, int); field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10 + field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20 field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4 field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8 field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2 @@ -2707,6 +2716,30 @@ package android.accessibilityservice { field public java.lang.String[] packageNames; } + public final class GestureDescription { + method public static android.accessibilityservice.GestureDescription createClick(int, int); + method public static android.accessibilityservice.GestureDescription createLongClick(int, int); + method public static android.accessibilityservice.GestureDescription createPinch(int, int, int, int, float, long); + method public static android.accessibilityservice.GestureDescription createSwipe(int, int, int, int, long); + method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(int); + method public int getStrokeCount(); + field public static final long MAX_GESTURE_DURATION_MS = 60000L; // 0xea60L + field public static final int MAX_STROKE_COUNT = 10; // 0xa + } + + public static class GestureDescription.Builder { + ctor public GestureDescription.Builder(); + method public android.accessibilityservice.GestureDescription.Builder addStroke(android.accessibilityservice.GestureDescription.StrokeDescription); + method public android.accessibilityservice.GestureDescription build(); + } + + public static class GestureDescription.StrokeDescription { + ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long); + method public long getDuration(); + method public android.graphics.Path getPath(); + method public long getStartTime(); + } + } package android.accounts { @@ -6135,6 +6168,7 @@ package android.app.job { method public int describeContents(); method public int getBackoffPolicy(); method public android.os.PersistableBundle getExtras(); + method public long getFlexMillis(); method public int getId(); method public long getInitialBackoffMillis(); method public long getIntervalMillis(); @@ -6152,6 +6186,8 @@ package android.app.job { field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR; field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L + field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L + field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L field public static final int NETWORK_TYPE_ANY = 1; // 0x1 field public static final int NETWORK_TYPE_NONE = 0; // 0x0 field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2 @@ -6165,6 +6201,7 @@ package android.app.job { method public android.app.job.JobInfo.Builder setMinimumLatency(long); method public android.app.job.JobInfo.Builder setOverrideDeadline(long); method public android.app.job.JobInfo.Builder setPeriodic(long); + method public android.app.job.JobInfo.Builder setPeriodic(long, long); method public android.app.job.JobInfo.Builder setPersisted(boolean); method public android.app.job.JobInfo.Builder setRequiredNetworkType(int); method public android.app.job.JobInfo.Builder setRequiresCharging(boolean); @@ -6225,6 +6262,8 @@ package android.app.usage { public static class NetworkStats.Bucket { ctor public NetworkStats.Bucket(); method public long getEndTimeStamp(); + method public int getMetering(); + method public int getRoaming(); method public long getRxBytes(); method public long getRxPackets(); method public long getStartTimeStamp(); @@ -6232,6 +6271,12 @@ package android.app.usage { method public long getTxBytes(); method public long getTxPackets(); method public int getUid(); + field public static final int METERING_ALL = -1; // 0xffffffff + field public static final int METERING_DEFAULT = 1; // 0x1 + field public static final int METERING_METERED = 2; // 0x2 + field public static final int ROAMING_ALL = -1; // 0xffffffff + field public static final int ROAMING_DEFAULT = 1; // 0x1 + field public static final int ROAMING_ROAMING = 2; // 0x2 field public static final int STATE_ALL = -1; // 0xffffffff field public static final int STATE_DEFAULT = 1; // 0x1 field public static final int STATE_FOREGROUND = 2; // 0x2 @@ -9451,8 +9496,6 @@ package android.content.pm { method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon(); method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int); method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); - method public abstract byte[] getEphemeralCookie(); - method public abstract int getEphemeralCookieMaxSizeBytes(); method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int); method public abstract java.lang.String getInstallerPackageName(java.lang.String); @@ -9486,7 +9529,6 @@ package android.content.pm { method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle); method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract boolean hasSystemFeature(java.lang.String); - method public abstract boolean isEphemeralApplication(); method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public abstract boolean isSafeMode(); method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); @@ -9504,7 +9546,6 @@ package android.content.pm { method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int); method public abstract void setApplicationEnabledSetting(java.lang.String, int, int); method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int); - method public abstract boolean setEphemeralCookie(byte[]); method public abstract void setInstallerPackageName(java.lang.String, java.lang.String); method public abstract void verifyPendingInstall(int, int); field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0 @@ -27206,7 +27247,7 @@ package android.opengl { ctor public GLException(int, java.lang.String); } - public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback { + public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback2 { ctor public GLSurfaceView(android.content.Context); ctor public GLSurfaceView(android.content.Context, android.util.AttributeSet); method public int getDebugFlags(); @@ -27230,6 +27271,7 @@ package android.opengl { method public void surfaceChanged(android.view.SurfaceHolder, int, int, int); method public void surfaceCreated(android.view.SurfaceHolder); method public void surfaceDestroyed(android.view.SurfaceHolder); + method public void surfaceRedrawNeeded(android.view.SurfaceHolder); field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1 field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2 field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1 @@ -31348,6 +31390,7 @@ package android.provider { field public static final java.lang.String AUTO_TIME = "auto_time"; field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone"; field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on"; + field public static final java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync"; field public static final android.net.Uri CONTENT_URI; field public static final java.lang.String DATA_ROAMING = "data_roaming"; field public static final java.lang.String DEBUG_APP = "debug_app"; @@ -33592,6 +33635,7 @@ package android.service.notification { field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb field public static final int REASON_PACKAGE_BANNED = 7; // 0x7 field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5 + field public static final int REASON_TOPIC_BANNED = 14; // 0xe field public static final int REASON_USER_STOPPED = 6; // 0x6 field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } @@ -36818,8 +36862,6 @@ package android.test.mock { method public android.graphics.drawable.Drawable getDefaultActivityIcon(); method public java.lang.String getDefaultBrowserPackageNameAsUser(int); method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); - method public byte[] getEphemeralCookie(); - method public int getEphemeralCookieMaxSizeBytes(); method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int); method public java.lang.String getInstallerPackageName(java.lang.String); @@ -36852,7 +36894,6 @@ package android.test.mock { method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle); method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public boolean hasSystemFeature(java.lang.String); - method public boolean isEphemeralApplication(); method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public boolean isSafeMode(); method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); @@ -36870,7 +36911,6 @@ package android.test.mock { method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int); method public void setApplicationEnabledSetting(java.lang.String, int, int); method public void setComponentEnabledSetting(android.content.ComponentName, int, int); - method public boolean setEphemeralCookie(byte[]); method public void setInstallerPackageName(java.lang.String, java.lang.String); method public void verifyPendingInstall(int, int); } @@ -39101,7 +39141,9 @@ package android.util { method public static android.util.LocaleList getEmptyLocaleList(); method public java.util.Locale getFirstMatch(java.lang.String[]); method public java.util.Locale getPrimary(); + method public int indexOf(java.util.Locale); method public boolean isEmpty(); + method public static void setDefault(android.util.LocaleList); method public int size(); method public java.lang.String toLanguageTags(); method public void writeToParcel(android.os.Parcel, int); diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 468c145a698b..3293c264974a 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -16,11 +16,13 @@ package android.accessibilityservice; +import android.accessibilityservice.GestureDescription.MotionEventGenerator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.pm.ParceledListSlice; import android.graphics.Region; import android.os.Handler; import android.os.IBinder; @@ -29,8 +31,11 @@ import android.os.Message; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; +import android.util.Pair; import android.util.Slog; +import android.util.SparseArray; import android.view.KeyEvent; +import android.view.MotionEvent; import android.view.WindowManager; import android.view.WindowManagerImpl; import android.view.accessibility.AccessibilityEvent; @@ -41,10 +46,7 @@ import android.view.accessibility.AccessibilityWindowInfo; import com.android.internal.os.HandlerCaller; import com.android.internal.os.SomeArgs; -import java.util.ArrayList; import java.util.List; -import java.util.Map.Entry; -import java.util.Set; /** * An accessibility service runs in the background and receives callbacks by the system @@ -376,6 +378,7 @@ public abstract class AccessibilityService extends Service { public boolean onKeyEvent(KeyEvent event); public void onMagnificationChanged(@NonNull Region region, float scale, float centerX, float centerY); + public void onPerformGestureResult(int sequence, boolean completedSuccessfully); } private int mConnectionId; @@ -388,6 +391,12 @@ public abstract class AccessibilityService extends Service { private MagnificationController mMagnificationController; + private int mGestureStatusCallbackSequence; + + private SparseArray<GestureResultCallbackInfo> mGestureStatusCallbackInfos; + + private final Object mLock = new Object(); + /** * Callback for {@link android.view.accessibility.AccessibilityEvent}s. * @@ -551,6 +560,88 @@ public abstract class AccessibilityService extends Service { return mMagnificationController; } + /** + * Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from + * the user, this service, or another service, will be cancelled. + * <p> + * <strong>Note:</strong> In order to dispatch gestures, your service + * must declare the capability by setting the + * {@link android.R.styleable#AccessibilityService_canPerformGestures} + * property in its meta-data. For more information, see + * {@link #SERVICE_META_DATA}. + * + * @param gesture The gesture to dispatch + * @param callback The object to call back when the status of the gesture is known. If + * {@code null}, no status is reported. + * @param handler The handler on which to call back the {@code callback} object. If + * {@code null}, the object is called back on the service's main thread. + * + * @return {@code true} if the gesture is dispatched, {@code false} if not. + */ + public final boolean dispatchGesture(@NonNull GestureDescription gesture, + @Nullable GestureResultCallback callback, + @Nullable Handler handler) { + final IAccessibilityServiceConnection connection = + AccessibilityInteractionClient.getInstance().getConnection( + mConnectionId); + if (connection == null) { + return false; + } + List<MotionEvent> events = MotionEventGenerator.getMotionEventsFromGestureDescription( + gesture, 100); + try { + synchronized (mLock) { + connection.sendMotionEvents(++mGestureStatusCallbackSequence, + new ParceledListSlice<>(events)); + if (callback != null) { + if (mGestureStatusCallbackInfos == null) { + mGestureStatusCallbackInfos = new SparseArray<>(); + } + GestureResultCallbackInfo callbackInfo = new GestureResultCallbackInfo(gesture, + callback, handler); + mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo); + } + } + } catch (RemoteException re) { + throw new RuntimeException(re); + } + return true; + } + + void onPerformGestureResult(int sequence, final boolean completedSuccessfully) { + if (mGestureStatusCallbackInfos == null) { + return; + } + GestureResultCallbackInfo callbackInfo; + synchronized (mLock) { + callbackInfo = mGestureStatusCallbackInfos.get(sequence); + } + final GestureResultCallbackInfo finalCallbackInfo = callbackInfo; + if ((callbackInfo != null) && (callbackInfo.gestureDescription != null) + && (callbackInfo.callback != null)) { + if (callbackInfo.handler != null) { + callbackInfo.handler.post(new Runnable() { + @Override + public void run() { + if (completedSuccessfully) { + finalCallbackInfo.callback + .onCompleted(finalCallbackInfo.gestureDescription); + } else { + finalCallbackInfo.callback + .onCancelled(finalCallbackInfo.gestureDescription); + } + } + }); + return; + } + if (completedSuccessfully) { + callbackInfo.callback.onCompleted(callbackInfo.gestureDescription); + } else { + callbackInfo.callback.onCancelled(callbackInfo.gestureDescription); + } + } + } + private void onMagnificationChanged(@NonNull Region region, float scale, float centerX, float centerY) { if (mMagnificationController != null) { @@ -1082,6 +1173,11 @@ public abstract class AccessibilityService extends Service { float scale, float centerX, float centerY) { AccessibilityService.this.onMagnificationChanged(region, scale, centerX, centerY); } + + @Override + public void onPerformGestureResult(int sequence, boolean completedSuccessfully) { + AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully); + } }); } @@ -1100,6 +1196,7 @@ public abstract class AccessibilityService extends Service { private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5; private static final int DO_ON_KEY_EVENT = 6; private static final int DO_ON_MAGNIFICATION_CHANGED = 7; + private static final int DO_GESTURE_COMPLETE = 8; private final HandlerCaller mCaller; @@ -1158,6 +1255,12 @@ public abstract class AccessibilityService extends Service { mCaller.sendMessage(message); } + public void onPerformGestureResult(int sequence, boolean successfully) { + Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence, + successfully ? 1 : 0); + mCaller.sendMessage(message); + } + @Override public void executeMessage(Message message) { switch (message.what) { @@ -1242,9 +1345,47 @@ public abstract class AccessibilityService extends Service { mCallback.onMagnificationChanged(region, scale, centerX, centerY); } return; + case DO_GESTURE_COMPLETE: { + final boolean successfully = message.arg2 == 1; + mCallback.onPerformGestureResult(message.arg1, successfully); + } return; + default : Log.w(LOG_TAG, "Unknown message type " + message.what); } } } + + /** + * Class used to report status of dispatched gestures + */ + public static abstract class GestureResultCallback { + /** Called when the gesture has completed successfully + * + * @param gestureDescription The description of the gesture that completed. + */ + public void onCompleted(GestureDescription gestureDescription) { + } + + /** Called when the gesture was cancelled + * + * @param gestureDescription The description of the gesture that was cancelled. + */ + public void onCancelled(GestureDescription gestureDescription) { + } + } + + /* Object to keep track of gesture result callbacks */ + private static class GestureResultCallbackInfo { + GestureDescription gestureDescription; + GestureResultCallback callback; + Handler handler; + + GestureResultCallbackInfo(GestureDescription gestureDescription, + GestureResultCallback callback, Handler handler) { + this.gestureDescription = gestureDescription; + this.callback = callback; + this.handler = handler; + } + } } diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 2c98fef20cdd..079bdfcb7b90 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -110,6 +110,12 @@ public class AccessibilityServiceInfo implements Parcelable { */ public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 0x00000010; + /** + * Capability: This accessibility service can perform gestures. + * @see android.R.styleable#AccessibilityService_canPerformGestures + */ + public static final int CAPABILITY_CAN_PERFORM_GESTURES = 0x00000020; + private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>(); static { @@ -133,6 +139,10 @@ public class AccessibilityServiceInfo implements Parcelable { new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION, R.string.capability_title_canControlMagnification, R.string.capability_desc_canControlMagnification)); + sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES, + new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES, + R.string.capability_title_canPerformGestures, + R.string.capability_desc_canPerformGestures)); } /** @@ -276,12 +286,7 @@ public class AccessibilityServiceInfo implements Parcelable { /** * This flag requests from the system to filter key events. If this flag * is set the accessibility service will receive the key events before - * applications allowing it implement global shortcuts. Setting this flag - * does not guarantee that this service will filter key events since only - * one service can do so at any given time. This avoids user confusion due - * to behavior change in case different key filtering services are enabled. - * If there is already another key filtering service enabled, this one will - * not receive key events. + * applications allowing it implement global shortcuts. * <p> * Services that want to set this flag have to declare this capability * in their meta-data by setting the attribute {@link android.R.attr @@ -516,6 +521,10 @@ public class AccessibilityServiceInfo implements Parcelable { .AccessibilityService_canControlMagnification, false)) { mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION; } + if (asAttributes.getBoolean(com.android.internal.R.styleable + .AccessibilityService_canPerformGestures, false)) { + mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES; + } TypedValue peekedValue = asAttributes.peekValue( com.android.internal.R.styleable.AccessibilityService_description); if (peekedValue != null) { @@ -616,6 +625,8 @@ public class AccessibilityServiceInfo implements Parcelable { * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY * @see #CAPABILITY_FILTER_KEY_EVENTS + * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION + * @see #CAPABILITY_CAN_PERFORM_GESTURES */ public int getCapabilities() { return mCapabilities; @@ -631,6 +642,8 @@ public class AccessibilityServiceInfo implements Parcelable { * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY * @see #CAPABILITY_FILTER_KEY_EVENTS + * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION + * @see #CAPABILITY_CAN_PERFORM_GESTURES * * @hide */ @@ -933,6 +946,8 @@ public class AccessibilityServiceInfo implements Parcelable { return "CAPABILITY_CAN_FILTER_KEY_EVENTS"; case CAPABILITY_CAN_CONTROL_MAGNIFICATION: return "CAPABILITY_CAN_CONTROL_MAGNIFICATION"; + case CAPABILITY_CAN_PERFORM_GESTURES: + return "CAPABILITY_CAN_PERFORM_GESTURES"; default: return "UNKNOWN"; } diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java new file mode 100644 index 000000000000..14aabcf69a6c --- /dev/null +++ b/core/java/android/accessibilityservice/GestureDescription.java @@ -0,0 +1,612 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.accessibilityservice; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.graphics.Matrix; +import android.graphics.Path; +import android.graphics.PathMeasure; +import android.graphics.RectF; +import android.view.InputDevice; +import android.view.MotionEvent; +import android.view.MotionEvent.PointerCoords; +import android.view.MotionEvent.PointerProperties; +import android.view.ViewConfiguration; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Accessibility services with the + * {@link android.R.styleable#AccessibilityService_canPerformGestures} property can dispatch + * gestures. This class describes those gestures. Gestures are made up of one or more strokes. + * Gestures are immutable; use the {@code create} methods to get common gesture, or a + * {@code Builder} to create a new one. + * <p> + * Spatial dimensions throughout are in screen pixels. Time is measured in milliseconds. + */ +public final class GestureDescription { + /** Gestures may contain no more than this many strokes */ + public static final int MAX_STROKE_COUNT = 10; + + /** + * Upper bound on total gesture duration. Nearly all gestures will be much shorter. + */ + public static final long MAX_GESTURE_DURATION_MS = 60 * 1000; + + private final List<StrokeDescription> mStrokes = new ArrayList<>(); + private final float[] mTempPos = new float[2]; + + /** + * Create a description of a click gesture + * + * @param x The x coordinate to click. Must not be negative. + * @param y The y coordinate to click. Must not be negative. + * + * @return A description of a click at (x, y) + */ + public static GestureDescription createClick(@IntRange(from = 0) int x, + @IntRange(from = 0) int y) { + Path clickPath = new Path(); + clickPath.moveTo(x, y); + clickPath.lineTo(x + 1, y); + return new GestureDescription( + new StrokeDescription(clickPath, 0, ViewConfiguration.getTapTimeout())); + } + + /** + * Create a description of a long click gesture + * + * @param x The x coordinate to click. Must not be negative. + * @param y The y coordinate to click. Must not be negative. + * + * @return A description of a click at (x, y) + */ + public static GestureDescription createLongClick(@IntRange(from = 0) int x, + @IntRange(from = 0) int y) { + Path clickPath = new Path(); + clickPath.moveTo(x, y); + clickPath.lineTo(x + 1, y); + int longPressTime = ViewConfiguration.getLongPressTimeout(); + return new GestureDescription( + new StrokeDescription(clickPath, 0, longPressTime + (longPressTime / 2))); + } + + /** + * Create a description of a swipe gesture + * + * @param startX The x coordinate of the starting point. Must not be negative. + * @param startY The y coordinate of the starting point. Must not be negative. + * @param endX The x coordinate of the ending point. Must not be negative. + * @param endY The y coordinate of the ending point. Must not be negative. + * @param duration The time, in milliseconds, to complete the gesture. Must not be negative. + * + * @return A description of a swipe from ({@code startX}, {@code startY}) to + * ({@code endX}, {@code endY}) that takes {@code duration} milliseconds. Returns {@code null} + * if the path specified for the swipe is invalid. + */ + public static GestureDescription createSwipe(@IntRange(from = 0) int startX, + @IntRange(from = 0) int startY, + @IntRange(from = 0) int endX, + @IntRange(from = 0) int endY, + @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long duration) { + Path swipePath = new Path(); + swipePath.moveTo(startX, startY); + swipePath.lineTo(endX, endY); + return new GestureDescription(new StrokeDescription(swipePath, 0, duration)); + } + + /** + * Create a description for a pinch (or zoom) gesture. + * + * @param centerX The x coordinate of the center of the pinch. Must not be negative. + * @param centerY The y coordinate of the center of the pinch. Must not be negative. + * @param startSpacing The spacing of the touch points at the beginning of the gesture. Must not + * be negative. + * @param endSpacing The spacing of the touch points at the end of the gesture. Must not be + * negative. + * @param orientation The angle, in degrees, of the gesture. 0 represents a horizontal pinch + * @param duration The time, in milliseconds, to complete the gesture. Must not be negative. + * + * @return A description of a pinch centered at ({code centerX}, {@code centerY}) that starts + * with the touch points spaced by {@code startSpacing} and ends with them spaced by + * {@code endSpacing} that lasts {@code duration} ms. Returns {@code null} if either path + * specified for the pinch is invalid. + */ + public static GestureDescription createPinch(@IntRange(from = 0) int centerX, + @IntRange(from = 0) int centerY, + @IntRange(from = 0) int startSpacing, + @IntRange(from = 0) int endSpacing, + float orientation, + @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long duration) { + if ((startSpacing < 0) || (endSpacing < 0)) { + throw new IllegalArgumentException("Pinch spacing cannot be negative"); + } + float[] startPoint1 = new float[2]; + float[] endPoint1 = new float[2]; + float[] startPoint2 = new float[2]; + float[] endPoint2 = new float[2]; + + /* Build points for a horizontal gesture centered at the origin */ + startPoint1[0] = startSpacing / 2; + startPoint1[1] = 0; + endPoint1[0] = endSpacing / 2; + endPoint1[1] = 0; + startPoint2[0] = -startSpacing / 2; + startPoint2[1] = 0; + endPoint2[0] = -endSpacing / 2; + endPoint2[1] = 0; + + /* Rotate and translate the points */ + Matrix matrix = new Matrix(); + matrix.setRotate(orientation); + matrix.postTranslate(centerX, centerY); + matrix.mapPoints(startPoint1); + matrix.mapPoints(endPoint1); + matrix.mapPoints(startPoint2); + matrix.mapPoints(endPoint2); + + Path path1 = new Path(); + path1.moveTo(startPoint1[0], startPoint1[1]); + path1.lineTo(endPoint1[0], endPoint1[1]); + Path path2 = new Path(); + path2.moveTo(startPoint2[0], startPoint2[1]); + path2.lineTo(endPoint2[0], endPoint2[1]); + + return new GestureDescription(Arrays.asList( + new StrokeDescription(path1, 0, duration), + new StrokeDescription(path2, 0, duration))); + } + + private GestureDescription() {} + + private GestureDescription(List<StrokeDescription> strokes) { + mStrokes.addAll(strokes); + } + + private GestureDescription(StrokeDescription stroke) { + mStrokes.add(stroke); + } + + /** + * Get the number of stroke in the gesture. + * + * @return the number of strokes in this gesture + */ + public int getStrokeCount() { + return mStrokes.size(); + } + + /** + * Read a stroke from the gesture + * + * @param index the index of the stroke + * + * @return A description of the stroke. + */ + public StrokeDescription getStroke(@IntRange(from = 0) int index) { + return mStrokes.get(index); + } + + /** + * Return the smallest key point (where a path starts or ends) that is at least a specified + * offset + * @param offset the minimum start time + * @return The next key time that is at least the offset or -1 if one can't be found + */ + private long getNextKeyPointAtLeast(long offset) { + long nextKeyPoint = Long.MAX_VALUE; + for (int i = 0; i < mStrokes.size(); i++) { + long thisStartTime = mStrokes.get(i).mStartTime; + if ((thisStartTime < nextKeyPoint) && (thisStartTime >= offset)) { + nextKeyPoint = thisStartTime; + } + long thisEndTime = mStrokes.get(i).mEndTime; + if ((thisEndTime < nextKeyPoint) && (thisEndTime >= offset)) { + nextKeyPoint = thisEndTime; + } + } + return (nextKeyPoint == Long.MAX_VALUE) ? -1L : nextKeyPoint; + } + + /** + * Get the points that correspond to a particular moment in time. + * @param time The time of interest + * @param touchPoints An array to hold the current touch points. Must be preallocated to at + * least the number of paths in the gesture to prevent going out of bounds + * @return The number of points found, and thus the number of elements set in each array + */ + private int getPointsForTime(long time, TouchPoint[] touchPoints) { + int numPointsFound = 0; + for (int i = 0; i < mStrokes.size(); i++) { + StrokeDescription strokeDescription = mStrokes.get(i); + if (strokeDescription.hasPointForTime(time)) { + touchPoints[numPointsFound].mPathIndex = i; + touchPoints[numPointsFound].mIsStartOfPath = (time == strokeDescription.mStartTime); + touchPoints[numPointsFound].mIsEndOfPath = (time == strokeDescription.mEndTime); + strokeDescription.getPosForTime(time, mTempPos); + touchPoints[numPointsFound].mX = Math.round(mTempPos[0]); + touchPoints[numPointsFound].mY = Math.round(mTempPos[1]); + numPointsFound++; + } + } + return numPointsFound; + } + + // Total duration assumes that the gesture starts at 0; waiting around to start a gesture + // counts against total duration + private static long getTotalDuration(List<StrokeDescription> paths) { + long latestEnd = Long.MIN_VALUE; + for (int i = 0; i < paths.size(); i++) { + StrokeDescription path = paths.get(i); + latestEnd = Math.max(latestEnd, path.mEndTime); + } + return Math.max(latestEnd, 0); + } + + /** + * Builder for a {@code GestureDescription} + */ + public static class Builder { + + private final List<StrokeDescription> mStrokes = new ArrayList<>(); + + /** + * Add a stroke to the gesture description. Up to {@code MAX_STROKE_COUNT} paths may be + * added to a gesture, and the total gesture duration (earliest path start time to latest path + * end time) may not exceed {@code MAX_GESTURE_DURATION_MS}. + * + * @param strokeDescription the stroke to add. + * + * @return this + */ + public Builder addStroke(@NonNull StrokeDescription strokeDescription) { + if (mStrokes.size() >= MAX_STROKE_COUNT) { + throw new RuntimeException("Attempting to add too many strokes to a gesture"); + } + + mStrokes.add(strokeDescription); + + if (getTotalDuration(mStrokes) > MAX_GESTURE_DURATION_MS) { + mStrokes.remove(strokeDescription); + throw new RuntimeException("Gesture would exceed maximum duration with new stroke"); + } + return this; + } + + public GestureDescription build() { + if (mStrokes.size() == 0) { + throw new RuntimeException("Gestures must have at least one stroke"); + } + return new GestureDescription(mStrokes); + } + } + + /** + * Immutable description of stroke that can be part of a gesture. + */ + public static class StrokeDescription { + Path mPath; + long mStartTime; + long mEndTime; + private float mTimeToLengthConversion; + private PathMeasure mPathMeasure; + + /** + * @param path The path to follow. Must have exactly one contour, and that contour must + * have nonzero length. The bounds of the path must not be negative. + * @param startTime The time, in milliseconds, from the time the gesture starts to the + * time the stroke should start. Must not be negative. + * @param duration The duration, in milliseconds, the stroke takes to traverse the path. + * Must not be negative. + */ + public StrokeDescription(@NonNull Path path, + @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long startTime, + @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long duration) { + if (duration <= 0) { + throw new IllegalArgumentException("Duration must be positive"); + } + if (startTime < 0) { + throw new IllegalArgumentException("Start time must not be negative"); + } + RectF bounds = new RectF(); + path.computeBounds(bounds, false /* unused */); + if ((bounds.bottom < 0) || (bounds.top < 0) || (bounds.right < 0) + || (bounds.left < 0)) { + throw new IllegalArgumentException("Path bounds must not be negative"); + } + mPath = new Path(path); + mPathMeasure = new PathMeasure(path, false); + if (mPathMeasure.getLength() == 0) { + throw new IllegalArgumentException("Path has zero length"); + } + if (mPathMeasure.nextContour()) { + throw new IllegalArgumentException("Path has more than one contour"); + } + /* + * Calling nextContour has moved mPathMeasure off the first contour, which is the only + * one we care about. Set the path again to go back to the first contour. + */ + mPathMeasure.setPath(path, false); + mStartTime = startTime; + mEndTime = startTime + duration; + if (duration > 0) { + mTimeToLengthConversion = getLength() / duration; + } + } + + /** + * Retrieve a copy of the path for this stroke + * + * @return A copy of the path + */ + public Path getPath() { + return new Path(mPath); + } + + /** + * Get the stroke's start time + * + * @return the start time for this stroke. + */ + public long getStartTime() { + return mStartTime; + } + + /** + * Get the stroke's duration + * + * @return the duration for this stroke + */ + public long getDuration() { + return mEndTime - mStartTime; + } + + float getLength() { + return mPathMeasure.getLength(); + } + + /* Assumes hasPointForTime returns true */ + boolean getPosForTime(long time, float[] pos) { + if (time == mEndTime) { + // Close to the end time, roundoff can be a problem + return mPathMeasure.getPosTan(getLength(), pos, null); + } + float length = mTimeToLengthConversion * ((float) (time - mStartTime)); + return mPathMeasure.getPosTan(length, pos, null); + } + + boolean hasPointForTime(long time) { + return ((time >= mStartTime) && (time <= mEndTime)); + } + } + + private static class TouchPoint { + int mPathIndex; + boolean mIsStartOfPath; + boolean mIsEndOfPath; + float mX; + float mY; + + void copyFrom(TouchPoint other) { + mPathIndex = other.mPathIndex; + mIsStartOfPath = other.mIsStartOfPath; + mIsEndOfPath = other.mIsEndOfPath; + mX = other.mX; + mY = other.mY; + } + } + + /** + * Class to convert a GestureDescription to a series of MotionEvents. + */ + static class MotionEventGenerator { + /** + * Constants used to initialize all MotionEvents + */ + private static final int EVENT_META_STATE = 0; + private static final int EVENT_BUTTON_STATE = 0; + private static final int EVENT_DEVICE_ID = 0; + private static final int EVENT_EDGE_FLAGS = 0; + private static final int EVENT_SOURCE = InputDevice.SOURCE_TOUCHSCREEN; + private static final int EVENT_FLAGS = 0; + private static final float EVENT_X_PRECISION = 1; + private static final float EVENT_Y_PRECISION = 1; + + /* Lazily-created scratch memory for processing touches */ + private static TouchPoint[] sCurrentTouchPoints; + private static TouchPoint[] sLastTouchPoints; + private static PointerCoords[] sPointerCoords; + private static PointerProperties[] sPointerProps; + + static List<MotionEvent> getMotionEventsFromGestureDescription( + GestureDescription description, int sampleTimeMs) { + final List<MotionEvent> motionEvents = new ArrayList<>(); + + // Point data at each time we generate an event for + final TouchPoint[] currentTouchPoints = + getCurrentTouchPoints(description.getStrokeCount()); + // Point data sent in last touch event + int lastTouchPointSize = 0; + final TouchPoint[] lastTouchPoints = + getLastTouchPoints(description.getStrokeCount()); + + /* Loop through each time slice where there are touch points */ + long timeSinceGestureStart = 0; + long nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart); + while (nextKeyPointTime >= 0) { + timeSinceGestureStart = (lastTouchPointSize == 0) ? nextKeyPointTime + : Math.min(nextKeyPointTime, timeSinceGestureStart + sampleTimeMs); + int currentTouchPointSize = description.getPointsForTime(timeSinceGestureStart, + currentTouchPoints); + + appendMoveEventIfNeeded(motionEvents, lastTouchPoints, lastTouchPointSize, + currentTouchPoints, currentTouchPointSize, timeSinceGestureStart); + lastTouchPointSize = appendUpEvents(motionEvents, lastTouchPoints, + lastTouchPointSize, currentTouchPoints, currentTouchPointSize, + timeSinceGestureStart); + lastTouchPointSize = appendDownEvents(motionEvents, lastTouchPoints, + lastTouchPointSize, currentTouchPoints, currentTouchPointSize, + timeSinceGestureStart); + + /* Move to next time slice */ + nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart + 1); + } + return motionEvents; + } + + private static TouchPoint[] getCurrentTouchPoints(int requiredCapacity) { + if ((sCurrentTouchPoints == null) || (sCurrentTouchPoints.length < requiredCapacity)) { + sCurrentTouchPoints = new TouchPoint[requiredCapacity]; + for (int i = 0; i < requiredCapacity; i++) { + sCurrentTouchPoints[i] = new TouchPoint(); + } + } + return sCurrentTouchPoints; + } + + private static TouchPoint[] getLastTouchPoints(int requiredCapacity) { + if ((sLastTouchPoints == null) || (sLastTouchPoints.length < requiredCapacity)) { + sLastTouchPoints = new TouchPoint[requiredCapacity]; + for (int i = 0; i < requiredCapacity; i++) { + sLastTouchPoints[i] = new TouchPoint(); + } + } + return sLastTouchPoints; + } + + private static PointerCoords[] getPointerCoords(int requiredCapacity) { + if ((sPointerCoords == null) || (sPointerCoords.length < requiredCapacity)) { + sPointerCoords = new PointerCoords[requiredCapacity]; + for (int i = 0; i < requiredCapacity; i++) { + sPointerCoords[i] = new PointerCoords(); + } + } + return sPointerCoords; + } + + private static PointerProperties[] getPointerProps(int requiredCapacity) { + if ((sPointerProps == null) || (sPointerProps.length < requiredCapacity)) { + sPointerProps = new PointerProperties[requiredCapacity]; + for (int i = 0; i < requiredCapacity; i++) { + sPointerProps[i] = new PointerProperties(); + } + } + return sPointerProps; + } + + private static void appendMoveEventIfNeeded(List<MotionEvent> motionEvents, + TouchPoint[] lastTouchPoints, int lastTouchPointsSize, + TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) { + /* Look for pointers that have moved */ + boolean moveFound = false; + for (int i = 0; i < currentTouchPointsSize; i++) { + int lastPointsIndex = findPointByPathIndex(lastTouchPoints, lastTouchPointsSize, + currentTouchPoints[i].mPathIndex); + if (lastPointsIndex >= 0) { + moveFound |= (lastTouchPoints[lastPointsIndex].mX != currentTouchPoints[i].mX) + || (lastTouchPoints[lastPointsIndex].mY != currentTouchPoints[i].mY); + lastTouchPoints[lastPointsIndex].copyFrom(currentTouchPoints[i]); + } + } + + if (moveFound) { + long downTime = motionEvents.get(motionEvents.size() - 1).getDownTime(); + motionEvents.add(obtainMotionEvent(downTime, currentTime, MotionEvent.ACTION_MOVE, + lastTouchPoints, lastTouchPointsSize)); + } + } + + private static int appendUpEvents(List<MotionEvent> motionEvents, + TouchPoint[] lastTouchPoints, int lastTouchPointsSize, + TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) { + /* Look for a pointer at the end of its path */ + for (int i = 0; i < currentTouchPointsSize; i++) { + if (currentTouchPoints[i].mIsEndOfPath) { + int indexOfUpEvent = findPointByPathIndex(lastTouchPoints, lastTouchPointsSize, + currentTouchPoints[i].mPathIndex); + if (indexOfUpEvent < 0) { + continue; // Should not happen + } + long downTime = motionEvents.get(motionEvents.size() - 1).getDownTime(); + int action = (lastTouchPointsSize == 1) ? MotionEvent.ACTION_UP + : MotionEvent.ACTION_POINTER_UP; + action |= indexOfUpEvent << MotionEvent.ACTION_POINTER_INDEX_SHIFT; + motionEvents.add(obtainMotionEvent(downTime, currentTime, action, + lastTouchPoints, lastTouchPointsSize)); + /* Remove this point from lastTouchPoints */ + for (int j = indexOfUpEvent; j < lastTouchPointsSize - 1; j++) { + lastTouchPoints[j].copyFrom(lastTouchPoints[j+1]); + } + lastTouchPointsSize--; + } + } + return lastTouchPointsSize; + } + + private static int appendDownEvents(List<MotionEvent> motionEvents, + TouchPoint[] lastTouchPoints, int lastTouchPointsSize, + TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) { + /* Look for a pointer that is just starting */ + for (int i = 0; i < currentTouchPointsSize; i++) { + if (currentTouchPoints[i].mIsStartOfPath) { + /* Add the point to last coords and use the new array to generate the event */ + lastTouchPoints[lastTouchPointsSize++].copyFrom(currentTouchPoints[i]); + int action = (lastTouchPointsSize == 1) ? MotionEvent.ACTION_DOWN + : MotionEvent.ACTION_POINTER_DOWN; + long downTime = (action == MotionEvent.ACTION_DOWN) ? currentTime : + motionEvents.get(motionEvents.size() - 1).getDownTime(); + action |= i << MotionEvent.ACTION_POINTER_INDEX_SHIFT; + motionEvents.add(obtainMotionEvent(downTime, currentTime, action, + lastTouchPoints, lastTouchPointsSize)); + } + } + return lastTouchPointsSize; + } + + private static MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, + TouchPoint[] touchPoints, int touchPointsSize) { + PointerCoords[] pointerCoords = getPointerCoords(touchPointsSize); + PointerProperties[] pointerProperties = getPointerProps(touchPointsSize); + for (int i = 0; i < touchPointsSize; i++) { + pointerProperties[i].id = touchPoints[i].mPathIndex; + pointerProperties[i].toolType = MotionEvent.TOOL_TYPE_UNKNOWN; + pointerCoords[i].clear(); + pointerCoords[i].pressure = 1.0f; + pointerCoords[i].size = 1.0f; + pointerCoords[i].x = touchPoints[i].mX; + pointerCoords[i].y = touchPoints[i].mY; + } + return MotionEvent.obtain(downTime, eventTime, action, touchPointsSize, + pointerProperties, pointerCoords, EVENT_META_STATE, EVENT_BUTTON_STATE, + EVENT_X_PRECISION, EVENT_Y_PRECISION, EVENT_DEVICE_ID, EVENT_EDGE_FLAGS, + EVENT_SOURCE, EVENT_FLAGS); + } + + private static int findPointByPathIndex(TouchPoint[] touchPoints, int touchPointsSize, + int pathIndex) { + for (int i = 0; i < touchPointsSize; i++) { + if (touchPoints[i].mPathIndex == pathIndex) { + return i; + } + } + return -1; + } + } +} diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl index 15666bf03ae8..6280542e6ce4 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl @@ -42,4 +42,6 @@ import android.view.KeyEvent; void onKeyEvent(in KeyEvent event, int sequence); void onMagnificationChanged(in Region region, float scale, float centerX, float centerY); + + void onPerformGestureResult(int sequence, boolean completedSuccessfully); } diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 6ac50bd6efbc..a65b87b7b0c8 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -16,10 +16,12 @@ package android.accessibilityservice; -import android.os.Bundle; import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.pm.ParceledListSlice; import android.graphics.Region; +import android.os.Bundle; import android.view.MagnificationSpec; +import android.view.MotionEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; import android.view.accessibility.AccessibilityWindowInfo; @@ -79,4 +81,6 @@ interface IAccessibilityServiceConnection { boolean animate); void setMagnificationCallbackEnabled(boolean enabled); + + void sendMotionEvents(int sequence, in ParceledListSlice events); } diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index 8928e99cecd2..e993cca9e325 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -861,22 +861,23 @@ public class PropertyValuesHolder implements Cloneable { if (mProperty != null) { Object value = convertBack(mProperty.get(target)); kf.setValue(value); - } - try { - if (mGetter == null) { - Class targetClass = target.getClass(); - setupGetter(targetClass); + } else { + try { if (mGetter == null) { - // Already logged the error - just return to avoid NPE - return; + Class targetClass = target.getClass(); + setupGetter(targetClass); + if (mGetter == null) { + // Already logged the error - just return to avoid NPE + return; + } } + Object value = convertBack(mGetter.invoke(target)); + kf.setValue(value); + } catch (InvocationTargetException e) { + Log.e("PropertyValuesHolder", e.toString()); + } catch (IllegalAccessException e) { + Log.e("PropertyValuesHolder", e.toString()); } - Object value = convertBack(mGetter.invoke(target)); - kf.setValue(value); - } catch (InvocationTargetException e) { - Log.e("PropertyValuesHolder", e.toString()); - } catch (IllegalAccessException e) { - Log.e("PropertyValuesHolder", e.toString()); } } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 64642ac5122d..34527c2623c6 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2843,16 +2843,15 @@ public class Activity extends ContextThemeWrapper if (keyCode == KeyEvent.KEYCODE_MENU && mActionBar != null && mActionBar.onMenuKeyEvent(event)) { return true; - } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { - // Capture the Alt-up and send focus to the ActionBar + } else if (event.isCtrlPressed() && + event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '<') { + // Capture the Control-< and send focus to the ActionBar final int action = event.getAction(); if (action == KeyEvent.ACTION_DOWN) { - if (event.hasModifiers(KeyEvent.META_ALT_ON)) { - final ActionBar actionBar = getActionBar(); - if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) { - mEatKeyUpEvent = true; - return true; - } + final ActionBar actionBar = getActionBar(); + if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) { + mEatKeyUpEvent = true; + return true; } } else if (action == KeyEvent.ACTION_UP && mEatKeyUpEvent) { mEatKeyUpEvent = false; diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 8475840bbae2..dce2e518d1e0 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -1031,6 +1031,11 @@ public final class UiAutomation { float scale, float centerX, float centerY) { /* do nothing */ } + + @Override + public void onPerformGestureResult(int sequence, boolean completedSuccessfully) { + /* do nothing */ + } }); } } diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java index 0d9e7787a236..b899710c4feb 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/core/java/android/app/job/JobInfo.java @@ -64,6 +64,11 @@ public class JobInfo implements Parcelable { */ public static final int BACKOFF_POLICY_EXPONENTIAL = 1; + /* Minimum interval for a periodic job, in milliseconds. */ + public static final long MIN_PERIOD_MILLIS = 60 * 60 * 1000L; // 60 minutes + /* Minimum flex for a periodic job, in milliseconds. */ + public static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes + /** * Default type of backoff. * @hide @@ -83,6 +88,7 @@ public class JobInfo implements Parcelable { private final boolean isPeriodic; private final boolean isPersisted; private final long intervalMillis; + private final long flexMillis; private final long initialBackoffMillis; private final int backoffPolicy; @@ -165,7 +171,17 @@ public class JobInfo implements Parcelable { * job does not recur periodically. */ public long getIntervalMillis() { - return intervalMillis; + return intervalMillis >= MIN_PERIOD_MILLIS ? intervalMillis : MIN_PERIOD_MILLIS; + } + + /** + * Flex time for this job. Only valid if this is a periodic job. + */ + public long getFlexMillis() { + long interval = getIntervalMillis(); + long percentClamp = 5 * interval / 100; + long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, MIN_FLEX_MILLIS)); + return clampedFlex <= interval ? clampedFlex : interval; } /** @@ -216,6 +232,7 @@ public class JobInfo implements Parcelable { isPeriodic = in.readInt() == 1; isPersisted = in.readInt() == 1; intervalMillis = in.readLong(); + flexMillis = in.readLong(); initialBackoffMillis = in.readLong(); backoffPolicy = in.readInt(); hasEarlyConstraint = in.readInt() == 1; @@ -234,6 +251,7 @@ public class JobInfo implements Parcelable { isPeriodic = b.mIsPeriodic; isPersisted = b.mIsPersisted; intervalMillis = b.mIntervalMillis; + flexMillis = b.mFlexMillis; initialBackoffMillis = b.mInitialBackoffMillis; backoffPolicy = b.mBackoffPolicy; hasEarlyConstraint = b.mHasEarlyConstraint; @@ -258,6 +276,7 @@ public class JobInfo implements Parcelable { out.writeInt(isPeriodic ? 1 : 0); out.writeInt(isPersisted ? 1 : 0); out.writeLong(intervalMillis); + out.writeLong(flexMillis); out.writeLong(initialBackoffMillis); out.writeInt(backoffPolicy); out.writeInt(hasEarlyConstraint ? 1 : 0); @@ -299,6 +318,7 @@ public class JobInfo implements Parcelable { private boolean mHasEarlyConstraint; private boolean mHasLateConstraint; private long mIntervalMillis; + private long mFlexMillis; // Back-off parameters. private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS; private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY; @@ -373,8 +393,21 @@ public class JobInfo implements Parcelable { * @param intervalMillis Millisecond interval for which this job will repeat. */ public Builder setPeriodic(long intervalMillis) { + return setPeriodic(intervalMillis, intervalMillis); + } + + /** + * Specify that this job should recur with the provided interval and flex. The job can + * execute at any time in a window of flex length at the end of the period. + * @param intervalMillis Millisecond interval for which this job will repeat. + * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least + * {@link #MIN_FLEX_MILLIS} or 5 percent of the period, whichever is + * higher. + */ + public Builder setPeriodic(long intervalMillis, long flexMillis) { mIsPeriodic = true; mIntervalMillis = intervalMillis; + mFlexMillis = flexMillis; mHasEarlyConstraint = mHasLateConstraint = true; return this; } diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index ef08eb9e8987..5f97c9e1d4fd 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -121,12 +121,12 @@ public final class NetworkStats implements AutoCloseable { */ public static class Bucket { /** - * Combined usage across all other states. + * Combined usage across all states. */ public static final int STATE_ALL = -1; /** - * Usage not accounted in any other states. + * Usage not accounted for in any other state. */ public static final int STATE_DEFAULT = 0x1; @@ -150,8 +150,40 @@ public final class NetworkStats implements AutoCloseable { */ public static final int UID_TETHERING = TrafficStats.UID_TETHERING; + /** + * Combined usage across all metering states. + */ + public static final int METERING_ALL = -1; + + /** + * Usage not accounted for in any other metering state. + */ + public static final int METERING_DEFAULT = 0x1; + + /** + * Metered usage. + */ + public static final int METERING_METERED = 0x2; + + /** + * Combined usage across all roaming states. + */ + public static final int ROAMING_ALL = -1; + + /** + * Usage not accounted for in any other roaming state. + */ + public static final int ROAMING_DEFAULT = 0x1; + + /** + * Roaming usage. + */ + public static final int ROAMING_ROAMING = 0x2; + private int mUid; private int mState; + private int mMetering; + private int mRoaming; private long mBeginTimeStamp; private long mEndTimeStamp; private long mRxBytes; @@ -206,6 +238,30 @@ public final class NetworkStats implements AutoCloseable { } /** + * Metering state. One of the following values:<p/> + * <ul> + * <li>{@link #METERING_ALL}</li> + * <li>{@link #METERING_DEFAULT}</li> + * <li>{@link #METERING_METERED}</li> + * </ul> + */ + public int getMetering() { + return mMetering; + } + + /** + * Roaming state. One of the following values:<p/> + * <ul> + * <li>{@link #ROAMING_ALL}</li> + * <li>{@link #ROAMING_DEFAULT}</li> + * <li>{@link #ROAMING_ROAMING}</li> + * </ul> + */ + public int getRoaming() { + return mRoaming; + } + + /** * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @return Start of interval. @@ -398,6 +454,9 @@ public final class NetworkStats implements AutoCloseable { private void fillBucketFromSummaryEntry(Bucket bucketOut) { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); + // TODO: Implement metering/roaming tracking. + bucketOut.mMetering = Bucket.METERING_ALL; + bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes; @@ -444,6 +503,8 @@ public final class NetworkStats implements AutoCloseable { mRecycledHistoryEntry); bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mState = Bucket.STATE_ALL; + bucketOut.mMetering = Bucket.METERING_ALL; + bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + mRecycledHistoryEntry.bucketDuration; diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index f41928ebe9d7..38abac7e741b 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3258,6 +3258,8 @@ public abstract class PackageManager { * @see #setEphemeralCookie(byte[]) * @see #getEphemeralCookie() * @see #getEphemeralCookieMaxSizeBytes() + * + * @hide */ public abstract boolean isEphemeralApplication(); @@ -3270,6 +3272,8 @@ public abstract class PackageManager { * @see #isEphemeralApplication() * @see #setEphemeralCookie(byte[]) * @see #getEphemeralCookie() + * + * @hide */ public abstract int getEphemeralCookieMaxSizeBytes(); @@ -3286,6 +3290,8 @@ public abstract class PackageManager { * @see #isEphemeralApplication() * @see #setEphemeralCookie(byte[]) * @see #getEphemeralCookieMaxSizeBytes() + * + * @hide */ public abstract @NonNull byte[] getEphemeralCookie(); @@ -3304,6 +3310,8 @@ public abstract class PackageManager { * @see #isEphemeralApplication() * @see #getEphemeralCookieMaxSizeBytes() * @see #getEphemeralCookie() + * + * @hide */ public abstract boolean setEphemeralCookie(@NonNull byte[] cookie); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 134966248f94..a0df610c7428 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -463,92 +463,60 @@ public class PackageParser { p.featureGroups.toArray(pi.featureGroups); } } - if ((flags&PackageManager.GET_ACTIVITIES) != 0) { - int N = p.activities.size(); + if ((flags & PackageManager.GET_ACTIVITIES) != 0) { + final int N = p.activities.size(); if (N > 0) { - if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.activities = new ActivityInfo[N]; - } else { - int num = 0; - for (int i=0; i<N; i++) { - if (p.activities.get(i).info.enabled) num++; - } - pi.activities = new ActivityInfo[num]; - } - for (int i=0, j=0; i<N; i++) { - final Activity activity = p.activities.get(i); - if (activity.info.enabled - || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags, - state, userId); + int num = 0; + final ActivityInfo[] res = new ActivityInfo[N]; + for (int i = 0; i < N; i++) { + final Activity a = p.activities.get(i); + if (state.isMatch(a.info, flags)) { + res[num++] = generateActivityInfo(a, flags, state, userId); } } + pi.activities = ArrayUtils.trimToSize(res, num); } } - if ((flags&PackageManager.GET_RECEIVERS) != 0) { - int N = p.receivers.size(); + if ((flags & PackageManager.GET_RECEIVERS) != 0) { + final int N = p.receivers.size(); if (N > 0) { - if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.receivers = new ActivityInfo[N]; - } else { - int num = 0; - for (int i=0; i<N; i++) { - if (p.receivers.get(i).info.enabled) num++; - } - pi.receivers = new ActivityInfo[num]; - } - for (int i=0, j=0; i<N; i++) { - final Activity activity = p.receivers.get(i); - if (activity.info.enabled - || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags, - state, userId); + int num = 0; + final ActivityInfo[] res = new ActivityInfo[N]; + for (int i = 0; i < N; i++) { + final Activity a = p.receivers.get(i); + if (state.isMatch(a.info, flags)) { + res[num++] = generateActivityInfo(a, flags, state, userId); } } + pi.receivers = ArrayUtils.trimToSize(res, num); } } - if ((flags&PackageManager.GET_SERVICES) != 0) { - int N = p.services.size(); + if ((flags & PackageManager.GET_SERVICES) != 0) { + final int N = p.services.size(); if (N > 0) { - if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.services = new ServiceInfo[N]; - } else { - int num = 0; - for (int i=0; i<N; i++) { - if (p.services.get(i).info.enabled) num++; - } - pi.services = new ServiceInfo[num]; - } - for (int i=0, j=0; i<N; i++) { - final Service service = p.services.get(i); - if (service.info.enabled - || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.services[j++] = generateServiceInfo(p.services.get(i), flags, - state, userId); + int num = 0; + final ServiceInfo[] res = new ServiceInfo[N]; + for (int i = 0; i < N; i++) { + final Service s = p.services.get(i); + if (state.isMatch(s.info, flags)) { + res[num++] = generateServiceInfo(s, flags, state, userId); } } + pi.services = ArrayUtils.trimToSize(res, num); } } - if ((flags&PackageManager.GET_PROVIDERS) != 0) { - int N = p.providers.size(); + if ((flags & PackageManager.GET_PROVIDERS) != 0) { + final int N = p.providers.size(); if (N > 0) { - if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.providers = new ProviderInfo[N]; - } else { - int num = 0; - for (int i=0; i<N; i++) { - if (p.providers.get(i).info.enabled) num++; - } - pi.providers = new ProviderInfo[num]; - } - for (int i=0, j=0; i<N; i++) { - final Provider provider = p.providers.get(i); - if (provider.info.enabled - || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, - state, userId); + int num = 0; + final ProviderInfo[] res = new ProviderInfo[N]; + for (int i = 0; i < N; i++) { + final Provider pr = p.providers.get(i); + if (state.isMatch(pr.info, flags)) { + res[num++] = generateProviderInfo(pr, flags, state, userId); } } + pi.providers = ArrayUtils.trimToSize(res, num); } } if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) { diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index 91fdf7f71f10..38e0044ea74c 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -17,9 +17,20 @@ package android.content.pm; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; +import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; +import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE; +import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import android.util.ArraySet; +import com.android.internal.util.ArrayUtils; + /** * Per-user state information about a package. * @hide @@ -58,12 +69,77 @@ public class PackageUserState { hidden = o.hidden; suspended = o.suspended; lastDisableAppCaller = o.lastDisableAppCaller; - disabledComponents = o.disabledComponents != null - ? new ArraySet<>(o.disabledComponents) : null; - enabledComponents = o.enabledComponents != null - ? new ArraySet<>(o.enabledComponents) : null; + disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents); + enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents); blockUninstall = o.blockUninstall; domainVerificationStatus = o.domainVerificationStatus; appLinkGeneration = o.appLinkGeneration; } + + /** + * Test if this package is installed. + */ + public boolean isInstalled(int flags) { + return (this.installed && !this.hidden) + || (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0; + } + + /** + * Test if the given component is considered installed, enabled and a match + * for the given flags. + */ + public boolean isMatch(ComponentInfo componentInfo, int flags) { + if (!isInstalled(flags)) return false; + if (!isEnabled(componentInfo, flags)) return false; + + if ((flags & MATCH_SYSTEM_ONLY) != 0) { + if (!componentInfo.applicationInfo.isSystemApp()) { + return false; + } + } + + final boolean matchesUnaware = ((flags & MATCH_ENCRYPTION_UNAWARE) != 0) + && !componentInfo.encryptionAware; + final boolean matchesAware = ((flags & MATCH_ENCRYPTION_AWARE) != 0) + && componentInfo.encryptionAware; + return matchesUnaware || matchesAware; + } + + /** + * Test if the given component is considered enabled. + */ + public boolean isEnabled(ComponentInfo componentInfo, int flags) { + if ((flags & MATCH_DISABLED_COMPONENTS) != 0) { + return true; + } + + // First check if the overall package is disabled; if the package is + // enabled then fall through to check specific component + switch (this.enabled) { + case COMPONENT_ENABLED_STATE_DISABLED: + case COMPONENT_ENABLED_STATE_DISABLED_USER: + return false; + case COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: + if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) { + return false; + } + case COMPONENT_ENABLED_STATE_DEFAULT: + if (!componentInfo.applicationInfo.enabled) { + return false; + } + case COMPONENT_ENABLED_STATE_ENABLED: + break; + } + + // Check if component has explicit state before falling through to + // the manifest default + if (ArrayUtils.contains(this.enabledComponents, componentInfo.name)) { + return true; + } + if (ArrayUtils.contains(this.disabledComponents, componentInfo.name)) { + return false; + } + + return componentInfo.enabled; + } } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 515e9a27eefc..cabc6fabc355 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -23,7 +23,6 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.net.NetworkUtils; import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.Handler; @@ -46,11 +45,11 @@ import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.Protocol; +import libcore.net.event.NetworkEventDispatcher; + import java.net.InetAddress; -import java.util.concurrent.atomic.AtomicInteger; import java.util.HashMap; - -import libcore.net.event.NetworkEventDispatcher; +import java.util.concurrent.atomic.AtomicInteger; /** * Class that answers queries about the state of network connectivity. It also @@ -1611,7 +1610,7 @@ public class ConnectivityManager { // Have a provisioning app - must only let system apps (which check this app) // turn on tethering context.enforceCallingOrSelfPermission( - android.Manifest.permission.CONNECTIVITY_INTERNAL, "ConnectivityService"); + android.Manifest.permission.TETHER_PRIVILEGED, "ConnectivityService"); } else { int uid = Binder.getCallingUid(); Settings.checkAndNoteWriteSettingsOperation(context, uid, Settings diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a0066741e11d..d4c994468030 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8288,7 +8288,6 @@ public final class Settings { /** * Whether to enable contacts metadata syncing or not * The value 1 - enable, 0 - disable - * @hide */ public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync"; diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index aba82fad0bfa..035462d56fc5 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -95,6 +95,9 @@ public abstract class NotificationAssistantService extends NotificationListenerS /** Notification was canceled because it was an invisible member of a group. */ public static final int REASON_GROUP_OPTIMIZATION = 13; + /** Notification was canceled by the user banning the topic. */ + public static final int REASON_TOPIC_BANNED = 14; + public class Adjustment { int mImportance; CharSequence mExplanation; diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java index f22cde0c1ca7..24883e317955 100644 --- a/core/java/android/util/LocaleList.java +++ b/core/java/android/util/LocaleList.java @@ -16,6 +16,7 @@ package android.util; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; @@ -56,10 +57,21 @@ public final class LocaleList implements Parcelable { return mList.length == 0; } + @IntRange(from=0) public int size() { return mList.length; } + @IntRange(from=-1) + public int indexOf(Locale locale) { + for (int i = 0; i < mList.length; i++) { + if (mList[i].equals(locale)) { + return i; + } + } + return -1; + } + @Override public boolean equals(Object other) { if (other == this) @@ -69,7 +81,7 @@ public final class LocaleList implements Parcelable { final Locale[] otherList = ((LocaleList) other).mList; if (mList.length != otherList.length) return false; - for (int i = 0; i < mList.length; ++i) { + for (int i = 0; i < mList.length; i++) { if (!mList[i].equals(otherList[i])) return false; } @@ -79,7 +91,7 @@ public final class LocaleList implements Parcelable { @Override public int hashCode() { int result = 1; - for (int i = 0; i < mList.length; ++i) { + for (int i = 0; i < mList.length; i++) { result = 31 * result + mList[i].hashCode(); } return result; @@ -89,7 +101,7 @@ public final class LocaleList implements Parcelable { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("["); - for (int i = 0; i < mList.length; ++i) { + for (int i = 0; i < mList.length; i++) { sb.append(mList[i]); if (i < mList.length - 1) { sb.append(','); @@ -150,12 +162,12 @@ public final class LocaleList implements Parcelable { final Locale[] localeList = new Locale[list.length]; final HashSet<Locale> seenLocales = new HashSet<Locale>(); final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < list.length; ++i) { + for (int i = 0; i < list.length; i++) { final Locale l = list[i]; if (l == null) { - throw new NullPointerException(); + throw new NullPointerException("list[" + i + "] is null"); } else if (seenLocales.contains(l)) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("list[" + i + "] is a repetition"); } else { final Locale localeClone = (Locale) l.clone(); localeList[i] = localeClone; @@ -171,6 +183,55 @@ public final class LocaleList implements Parcelable { } } + /** + * Constructs a locale list, with the topLocale moved to the front if it already is + * in otherLocales, or added to the front if it isn't. + * + * {@hide} + */ + public LocaleList(@NonNull Locale topLocale, LocaleList otherLocales) { + if (topLocale == null) { + throw new NullPointerException("topLocale is null"); + } + + final int inputLength = (otherLocales == null) ? 0 : otherLocales.mList.length; + int topLocaleIndex = -1; + for (int i = 0; i < inputLength; i++) { + if (topLocale.equals(otherLocales.mList[i])) { + topLocaleIndex = i; + break; + } + } + + final int outputLength = inputLength + (topLocaleIndex == -1 ? 1 : 0); + final Locale[] localeList = new Locale[outputLength]; + localeList[0] = (Locale) topLocale.clone(); + if (topLocaleIndex == -1) { + // topLocale was not in otherLocales + for (int i = 0; i < inputLength; i++) { + localeList[i + 1] = (Locale) otherLocales.mList[i].clone(); + } + } else { + for (int i = 0; i < topLocaleIndex; i++) { + localeList[i + 1] = (Locale) otherLocales.mList[i].clone(); + } + for (int i = topLocaleIndex + 1; i < inputLength; i++) { + localeList[i] = (Locale) otherLocales.mList[i].clone(); + } + } + + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < outputLength; i++) { + sb.append(localeList[i].toLanguageTag()); + if (i < outputLength - 1) { + sb.append(','); + } + } + + mList = localeList; + mStringRepresentation = sb.toString(); + } + public static final Parcelable.Creator<LocaleList> CREATOR = new Parcelable.Creator<LocaleList>() { @Override @@ -196,7 +257,7 @@ public final class LocaleList implements Parcelable { } else { final String[] tags = list.split(","); final Locale[] localeArray = new Locale[tags.length]; - for (int i = 0; i < localeArray.length; ++i) { + for (int i = 0; i < localeArray.length; i++) { localeArray[i] = Locale.forLanguageTag(tags[i]); } return new LocaleList(localeArray); @@ -227,6 +288,7 @@ public final class LocaleList implements Parcelable { return LOCALE_EN_XA.equals(locale) || LOCALE_AR_XB.equals(locale); } + @IntRange(from=0, to=1) private static int matchScore(Locale supported, Locale desired) { if (supported.equals(desired)) { return 1; // return early so we don't do unnecessary computation @@ -330,18 +392,79 @@ public final class LocaleList implements Parcelable { private final static Object sLock = new Object(); @GuardedBy("sLock") - private static LocaleList sDefaultLocaleList; + private static LocaleList sLastExplicitlySetLocaleList = null; + @GuardedBy("sLock") + private static LocaleList sDefaultLocaleList = null; + @GuardedBy("sLock") + private static Locale sLastDefaultLocale = null; - // TODO: fix this to return the default system locale list once we have that + /** + * The result is guaranteed to include the default Locale returned by Locale.getDefault(), but + * not necessarily at the top of the list. The default locale not being at the top of the list + * is an indication that the system has set the default locale to one of the user's other + * preferred locales, having concluded that the primary preference is not supported but a + * secondary preference is. + * + * Note that the default LocaleList would change if Locale.setDefault() is called. This method + * takes that into account by always checking the output of Locale.getDefault() and adjusting + * the default LocaleList if needed. + */ @NonNull @Size(min=1) public static LocaleList getDefault() { - Locale defaultLocale = Locale.getDefault(); + final Locale defaultLocale = Locale.getDefault(); synchronized (sLock) { - if (sDefaultLocaleList == null || sDefaultLocaleList.size() != 1 - || !defaultLocale.equals(sDefaultLocaleList.getPrimary())) { - sDefaultLocaleList = new LocaleList(defaultLocale); + if (!defaultLocale.equals(sLastDefaultLocale)) { + sLastDefaultLocale = defaultLocale; + // It's either the first time someone has asked for the default locale list, or + // someone has called Locale.setDefault() since we last set or adjusted the default + // locale list. So let's adjust the locale list. + if (sDefaultLocaleList != null + && defaultLocale.equals(sDefaultLocaleList.getPrimary())) { + // The default Locale has changed, but it happens to be the first locale in the + // default locale list, so we don't need to construct a new locale list. + return sDefaultLocaleList; + } + sDefaultLocaleList = new LocaleList(defaultLocale, sLastExplicitlySetLocaleList); } + // sDefaultLocaleList can't be null, since it can't be set to null by + // LocaleList.setDefault(), and if getDefault() is called before a call to + // setDefault(), sLastDefaultLocale would be null and the check above would set + // sDefaultLocaleList. + return sDefaultLocaleList; + } + } + + /** + * Also sets the default locale by calling Locale.setDefault() with the first locale in the + * list. + * + * @throws NullPointerException if the input is <code>null</code>. + * @throws IllegalArgumentException if the input is empty. + */ + public static void setDefault(@NonNull @Size(min=1) LocaleList locales) { + setDefault(locales, 0); + } + + /** + * This may be used directly by system processes to set the default locale list for apps. For + * such uses, the default locale list would always come from the user preferences, but the + * default locale may have been chosen to be a locale other than the first locale in the locale + * list (based on the locales the app supports). + * + * {@hide} + */ + public static void setDefault(@NonNull @Size(min=1) LocaleList locales, int localeIndex) { + if (locales == null) { + throw new NullPointerException("locales is null"); + } + if (locales.isEmpty()) { + throw new IllegalArgumentException("locales is empty"); + } + synchronized (sLock) { + sLastDefaultLocale = locales.get(localeIndex); + Locale.setDefault(sLastDefaultLocale); + sLastExplicitlySetLocaleList = locales; + sDefaultLocaleList = locales; } - return sDefaultLocaleList; } } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index ecec25852cbb..a78b56ab194c 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -1328,4 +1328,15 @@ public interface WindowManagerPolicy { * @param fadeoutDuration the duration of the exit animation, in milliseconds */ public void startKeyguardExitAnimation(long startTime, long fadeoutDuration); + + /** + * Calculates the stable insets without running a layout. + * + * @param displayRotation the current display rotation + * @param outInsets the insets to return + * @param displayWidth the current display width + * @param displayHeight the current display height + */ + public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight, + Rect outInsets); } diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index ba5d6c2896ef..6e5e5915bb6f 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -201,10 +201,17 @@ public class BaseInputConnection implements InputConnection { } /** - * The default implementation performs the deletion around the current - * selection position of the editable text. - * @param beforeLength - * @param afterLength + * The default implementation performs the deletion around the current selection position of the + * editable text. + * + * @param beforeLength The number of characters before the cursor to be deleted, in code unit. + * If this is greater than the number of existing characters between the beginning of the + * text and the cursor, then this method does not fail but deletes all the characters in + * that range. + * @param afterLength The number of characters after the cursor to be deleted, in code unit. + * If this is greater than the number of existing characters between the cursor and + * the end of the text, then this method does not fail but deletes all the characters in + * that range. */ public boolean deleteSurroundingText(int beforeLength, int afterLength) { if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength @@ -213,7 +220,7 @@ public class BaseInputConnection implements InputConnection { if (content == null) return false; beginBatchEdit(); - + int a = Selection.getSelectionStart(content); int b = Selection.getSelectionEnd(content); @@ -253,9 +260,9 @@ public class BaseInputConnection implements InputConnection { content.delete(b, end); } - + endBatchEdit(); - + return true; } diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java index ff992d39fc66..be7bc14f0515 100644 --- a/core/java/android/view/inputmethod/InputConnection.java +++ b/core/java/android/view/inputmethod/InputConnection.java @@ -335,12 +335,15 @@ public interface InputConnection { * but be careful to wait until the batch edit is over if one is * in progress.</p> * - * @param beforeLength The number of characters to be deleted before the - * current cursor position. - * @param afterLength The number of characters to be deleted after the - * current cursor position. - * @return true on success, false if the input connection is no longer - * valid. + * @param beforeLength The number of characters before the cursor to be deleted, in code unit. + * If this is greater than the number of existing characters between the beginning of the + * text and the cursor, then this method does not fail but deletes all the characters in + * that range. + * @param afterLength The number of characters after the cursor to be deleted, in code unit. + * If this is greater than the number of existing characters between the cursor and + * the end of the text, then this method does not fail but deletes all the characters in + * that range. + * @return true on success, false if the input connection is no longer valid. */ public boolean deleteSurroundingText(int beforeLength, int afterLength); diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 9f08b214a849..054eafcf2232 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -131,6 +131,8 @@ public final class WebViewFactory { private static String TAG_WEBVIEW_PROVIDER = "webviewprovider"; private static String TAG_PACKAGE_NAME = "packageName"; private static String TAG_DESCRIPTION = "description"; + // Whether or not the provider must be explicitly chosen by the user to be used. + private static String TAG_AVAILABILITY = "availableByDefault"; private static String TAG_SIGNATURE = "signature"; /** @@ -180,8 +182,12 @@ public final class WebViewFactory { throw new MissingWebViewPackageException( "WebView provider in framework resources missing description"); } + String availableByDefault = parser.getAttributeValue(null, TAG_AVAILABILITY); + if (availableByDefault == null) { + availableByDefault = "false"; + } webViewProviders.add( - new WebViewProviderInfo(packageName, description, + new WebViewProviderInfo(packageName, description, availableByDefault, readSignatures(parser))); } else { diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java index ac5b67089d20..3f50fe2e376c 100644 --- a/core/java/android/webkit/WebViewProviderInfo.java +++ b/core/java/android/webkit/WebViewProviderInfo.java @@ -40,9 +40,11 @@ public class WebViewProviderInfo implements Parcelable { public WebViewPackageNotFoundException(Exception e) { super(e); } } - public WebViewProviderInfo(String packageName, String description, String[] signatures) { + public WebViewProviderInfo(String packageName, String description, String availableByDefault, + String[] signatures) { this.packageName = packageName; this.description = description; + this.availableByDefault = availableByDefault.equals("true"); this.signatures = signatures; } @@ -89,6 +91,39 @@ public class WebViewProviderInfo implements Parcelable { return false; } + /** + * Returns whether this package is enabled. + * This state can be changed by the user from Settings->Apps + */ + public boolean isEnabled() { + try { + PackageManager pm = AppGlobals.getInitialApplication().getPackageManager(); + int enabled_state = pm.getApplicationEnabledSetting(packageName); + switch (enabled_state) { + case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: + return true; + case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: + ApplicationInfo applicationInfo = getPackageInfo().applicationInfo; + return applicationInfo.enabled; + default: + return false; + } + } catch (WebViewPackageNotFoundException e) { + return false; + } catch (IllegalArgumentException e) { + // Thrown by PackageManager.getApplicationEnabledSetting if the package does not exist + return false; + } + } + + /** + * Returns whether the provider is always available as long as it is valid. + * If this returns false, the provider will only be used if the user chose this provider. + */ + public boolean isAvailableByDefault() { + return availableByDefault; + } + public PackageInfo getPackageInfo() { if (packageInfo == null) { try { @@ -135,6 +170,7 @@ public class WebViewProviderInfo implements Parcelable { // fields read from framework resource public String packageName; public String description; + private boolean availableByDefault; private String[] signatures; diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 40eb375c027b..ce4fc0633a6b 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -27,7 +27,6 @@ import android.view.View; */ public class MetricsLogger implements MetricsConstants { // Temporary constants go here, to await migration to MetricsConstants. - public static final int QS_LOCK_TILE = 257; public static final int QS_USER_TILE = 258; public static final int QS_BATTERY_TILE = 259; public static final int NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 260; @@ -62,6 +61,7 @@ public class MetricsLogger implements MetricsConstants { * credentials UI. */ public static final int PROFILE_CHALLENGE = 271; + public static final int QS_BATTERY_DETAIL = 272; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java index 1b44ff3ec3fb..de54d96df78b 100644 --- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java +++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java @@ -99,6 +99,9 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame mResizingBackgroundDrawable = resizingBackgroundDrawable; mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable; mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable; + if (mCaptionBackgroundDrawable == null) { + mCaptionBackgroundDrawable = mResizingBackgroundDrawable; + } if (statusBarColor != 0) { mStatusBarColor = new ColorDrawable(statusBarColor); addSystemBarNodeIfNeeded(); diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index cc2f7142f893..cea9867b8d88 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -1616,14 +1616,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind void onResourcesLoaded(LayoutInflater inflater, int layoutResource) { mStackId = getStackId(); - mResizingBackgroundDrawable = getResizingBackgroundDrawable( - mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource); - if (mCaptionBackgroundDrawable == null) { - mCaptionBackgroundDrawable = getContext().getDrawable( - R.drawable.decor_caption_title_focused); - } - if (mBackdropFrameRenderer != null) { + loadBackgroundDrawablesIfNeeded(); mBackdropFrameRenderer.onResourcesLoaded( this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable, mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState)); @@ -1645,6 +1639,17 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind initializeElevation(); } + private void loadBackgroundDrawablesIfNeeded() { + if (mResizingBackgroundDrawable == null) { + mResizingBackgroundDrawable = getResizingBackgroundDrawable( + mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource); + } + if (mCaptionBackgroundDrawable == null) { + mCaptionBackgroundDrawable = getContext().getDrawable( + R.drawable.decor_caption_title_focused); + } + } + // Free floating overlapping windows require a caption. private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) { DecorCaptionView decorCaptionView = null; @@ -1815,6 +1820,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } final ThreadedRenderer renderer = getHardwareRenderer(); if (renderer != null) { + loadBackgroundDrawablesIfNeeded(); mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer, initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable, mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState)); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java index e43d531c7a5c..e79f1b8a3133 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java +++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java @@ -14,18 +14,19 @@ * limitations under the License. */ -package com.android.systemui.stackdivider; +package com.android.internal.policy; import android.content.Context; +import android.content.res.Resources; import android.graphics.Rect; -import com.android.systemui.statusbar.FlingAnimationUtils; - import java.util.ArrayList; /** * Calculates the snap targets and the snap position given a position and a velocity. All positions * here are to be interpreted as the left/top edge of the divider rectangle. + * + * @hide */ public class DividerSnapAlgorithm { @@ -44,8 +45,7 @@ public class DividerSnapAlgorithm { */ private static final int SNAP_ONLY_1_1 = 2; - private final Context mContext; - private final FlingAnimationUtils mFlingAnimationUtils; + private final float mMinFlingVelocityPxPerSecond; private final int mDisplayWidth; private final int mDisplayHeight; private final int mDividerSize; @@ -63,18 +63,17 @@ public class DividerSnapAlgorithm { private final SnapTarget mDismissStartTarget; private final SnapTarget mDismissEndTarget; - public DividerSnapAlgorithm(Context ctx, FlingAnimationUtils flingAnimationUtils, + public DividerSnapAlgorithm(Resources res, float minFlingVelocityPxPerSecond, int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision, Rect insets) { - mContext = ctx; - mFlingAnimationUtils = flingAnimationUtils; + mMinFlingVelocityPxPerSecond = minFlingVelocityPxPerSecond; mDividerSize = dividerSize; mDisplayWidth = displayWidth; mDisplayHeight = displayHeight; mInsets.set(insets); - mSnapMode = ctx.getResources().getInteger( + mSnapMode = res.getInteger( com.android.internal.R.integer.config_dockedStackDividerSnapMode); - mFixedRatio = ctx.getResources().getFraction( + mFixedRatio = res.getFraction( com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1); calculateTargets(isHorizontalDivision); mFirstSplitTarget = mTargets.get(1); @@ -84,7 +83,7 @@ public class DividerSnapAlgorithm { } public SnapTarget calculateSnapTarget(int position, float velocity) { - if (Math.abs(velocity) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) { + if (Math.abs(velocity) < mMinFlingVelocityPxPerSecond) { return snap(position); } if (position < mFirstSplitTarget.position && velocity < 0) { @@ -100,6 +99,17 @@ public class DividerSnapAlgorithm { } } + public SnapTarget calculateNonDismissingSnapTarget(int position) { + SnapTarget target = snap(position); + if (target == mDismissStartTarget) { + return mFirstSplitTarget; + } else if (target == mDismissEndTarget) { + return mLastSplitTarget; + } else { + return target; + } + } + public float calculateDismissingFraction(int position) { if (position < mFirstSplitTarget.position) { return 1f - (float) position / mFirstSplitTarget.position; diff --git a/core/java/com/android/internal/policy/DockedDividerUtils.java b/core/java/com/android/internal/policy/DockedDividerUtils.java new file mode 100644 index 000000000000..25a060e0a0a7 --- /dev/null +++ b/core/java/com/android/internal/policy/DockedDividerUtils.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.policy; + +import android.graphics.Rect; +import android.view.WindowManager; + +/** + * Utility functions for docked stack divider used by both window manager and System UI. + * + * @hide + */ +public class DockedDividerUtils { + + public static void calculateBoundsForPosition(int position, int dockSide, Rect outRect, + int displayWidth, int displayHeight, int dividerSize) { + outRect.set(0, 0, displayWidth, displayHeight); + switch (dockSide) { + case WindowManager.DOCKED_LEFT: + outRect.right = position; + break; + case WindowManager.DOCKED_TOP: + outRect.bottom = position; + break; + case WindowManager.DOCKED_RIGHT: + outRect.left = position + dividerSize; + break; + case WindowManager.DOCKED_BOTTOM: + outRect.top = position + dividerSize; + break; + } + if (outRect.left > outRect.right) { + outRect.left = outRect.right; + } + if (outRect.top > outRect.bottom) { + outRect.top = outRect.bottom; + } + if (outRect.right < outRect.left) { + outRect.right = outRect.left; + } + if (outRect.bottom < outRect.top) { + outRect.bottom = outRect.top; + } + } + + public static int calculatePositionForBounds(Rect bounds, int dockSide, int dividerSize) { + switch (dockSide) { + case WindowManager.DOCKED_LEFT: + return bounds.right; + case WindowManager.DOCKED_TOP: + return bounds.bottom; + case WindowManager.DOCKED_RIGHT: + return bounds.left - dividerSize; + case WindowManager.DOCKED_BOTTOM: + return bounds.top - dividerSize; + default: + return 0; + } + } +} diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 16bf9dd2900b..ca1334c6e6cc 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -26,6 +26,7 @@ import libcore.util.EmptyArray; import java.lang.reflect.Array; import java.util.ArrayList; +import java.util.Arrays; import java.util.Objects; /** @@ -372,6 +373,10 @@ public class ArrayUtils { return (array != null) ? array.clone() : null; } + public static @Nullable <T> ArraySet<T> cloneOrNull(@Nullable ArraySet<T> array) { + return (array != null) ? new ArraySet<T>(array) : null; + } + public static @NonNull <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) { if (cur == null) { cur = new ArraySet<>(); @@ -420,6 +425,16 @@ public class ArrayUtils { return (cur != null) ? cur.contains(val) : false; } + public static @Nullable <T> T[] trimToSize(@Nullable T[] array, int size) { + if (array == null || size == 0) { + return null; + } else if (array.length == size) { + return array; + } else { + return Arrays.copyOf(array, size); + } + } + /** * Returns true if the two ArrayLists are equal with respect to the objects they contain. * The objects must be in the same order and be reference equal (== not .equals()). diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 21ba793c2a92..75077df213b4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1070,6 +1070,12 @@ <permission android:name="android.permission.READ_WIFI_CREDENTIAL" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi @hide Allows applications to change tether state and run + tether carrier provisioning. + <p>Not for use by third-party applications. --> + <permission android:name="android.permission.TETHER_PRIVILEGED" + android:protectionLevel="signature|privileged" /> + <!-- @SystemApi @hide Allow system apps to receive broadcast when a wifi network credential is changed. <p>Not for use by third-party applications. --> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 6d505a58ab80..e0f9eca0077d 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3316,7 +3316,14 @@ i </p> --> <attr name="canControlMagnification" format="boolean" /> - <!-- Short description of the accessibility serivce purpose or behavior.--> + <!-- Attribute whether the accessibility service wants to be able to perform gestures. + <p> + Required to allow setting the {@link android.accessibilityservice + #AccessibilityServiceInfo#FLAG_CAN_PERFORM_GESTURES} flag. + </p> + --> + <attr name="canPerformGestures" format="boolean" /> + <!-- Short description of the accessibility service purpose or behavior.--> <attr name="description" /> </declare-styleable> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index ebb1b372e717..acea461f44a1 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2688,6 +2688,7 @@ <public type="attr" name="tickMark" /> <public type="attr" name="tickMarkTint" /> <public type="attr" name="tickMarkTintMode" /> + <public type="attr" name="canPerformGestures" /> <public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" /> <public type="style" name="Widget.Material.SeekBar.Discrete" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index be9ba62baa3a..997371eebf2b 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -652,6 +652,12 @@ <string name="capability_desc_canControlMagnification">Control the display\'s zoom level and positioning.</string> + <!-- Title for the capability of an accessibility service to perform gestures. --> + <string name="capability_title_canPerformGestures">Perform gestures</string> + <!-- Description for the capability of an accessibility service to perform gestures. --> + <string name="capability_desc_canPerformGestures">Can tap, swipe, pinch, and perform other + gestures.</string> + <!-- Permissions --> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a4654e8a710f..706dd206fcb2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -561,6 +561,8 @@ <java-symbol type="string" name="capability_title_canRetrieveWindowContent" /> <java-symbol type="string" name="capability_desc_canControlMagnification" /> <java-symbol type="string" name="capability_title_canControlMagnification" /> + <java-symbol type="string" name="capability_desc_canPerformGestures" /> + <java-symbol type="string" name="capability_title_canPerformGestures" /> <java-symbol type="string" name="cfTemplateForwarded" /> <java-symbol type="string" name="cfTemplateForwardedTime" /> <java-symbol type="string" name="cfTemplateNotForwarded" /> diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml index fd443c15702d..f062b59a008c 100644 --- a/core/res/res/xml/config_webview_packages.xml +++ b/core/res/res/xml/config_webview_packages.xml @@ -16,6 +16,6 @@ <webviewproviders> <!-- The default WebView implementation --> - <webviewprovider description="Android WebView" packageName="com.android.webview"> + <webviewprovider description="Android WebView" packageName="com.android.webview" availableByDefault="true"> </webviewprovider> </webviewproviders> diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml index 6bd8f6ebcfa2..a391e1feb28f 100644 --- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml +++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml @@ -75,6 +75,7 @@ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <!-- This permission is added for API call setAirplaneMode() in ConnectivityManager --> <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> + <uses-permission android:name="android.permission.TETHER_PRIVILEGED" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.DEVICE_POWER" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> diff --git a/core/tests/coretests/src/android/util/LocaleListTest.java b/core/tests/coretests/src/android/util/LocaleListTest.java new file mode 100644 index 000000000000..de1382d5d45e --- /dev/null +++ b/core/tests/coretests/src/android/util/LocaleListTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.util; + +import android.test.suitebuilder.annotation.SmallTest; +import android.util.LocaleList; + +import java.util.Locale; + +import junit.framework.TestCase; + +public class LocaleListTest extends TestCase { + @SmallTest + public void testConstructor() throws Exception { + LocaleList ll; + ll = new LocaleList(Locale.forLanguageTag("fr"), null); + assertEquals("fr", ll.toLanguageTags()); + + ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.getEmptyLocaleList()); + assertEquals("fr", ll.toLanguageTags()); + + ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("fr")); + assertEquals("fr", ll.toLanguageTags()); + + ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("de")); + assertEquals("fr,de", ll.toLanguageTags()); + + ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("de,ja")); + assertEquals("fr,de,ja", ll.toLanguageTags()); + + ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("de,fr,ja")); + assertEquals("fr,de,ja", ll.toLanguageTags()); + + ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("de,fr")); + assertEquals("fr,de", ll.toLanguageTags()); + + ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("fr,de")); + assertEquals("fr,de", ll.toLanguageTags()); + } + + @SmallTest + public void testConstructor_nullThrows() throws Exception { + try { + final LocaleList ll = new LocaleList(null, LocaleList.getEmptyLocaleList()); + fail("Constructing with locale and locale list should throw with a null locale."); + } catch (Throwable e) { + assertEquals(NullPointerException.class, e.getClass()); + } + } + + @SmallTest + public void testGetDefault_localeSetDefaultCalledButNoChangeNecessary() throws Exception { + final Locale originalLocale = Locale.getDefault(); + final LocaleList originalLocaleList = LocaleList.getDefault(); + final int originalLocaleIndex = originalLocaleList.indexOf(originalLocale); + + // This simulates a situation potentially set by the system processes + LocaleList.setDefault(LocaleList.forLanguageTags("ae,en,ja"), 1 /* en */); + + // check our assumptions about input + assertEquals("en", Locale.getDefault().toLanguageTag()); + final LocaleList firstResult = LocaleList.getDefault(); + assertEquals("ae,en,ja", LocaleList.getDefault().toLanguageTags()); + + Locale.setDefault(Locale.forLanguageTag("ae")); + assertSame(firstResult, LocaleList.getDefault()); + + // restore the original values + LocaleList.setDefault(originalLocaleList, originalLocaleIndex); + } +} diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 11056d4fac97..0932e8998ce2 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -109,7 +109,8 @@ ifeq (true, $(HWUI_NEW_OPS)) BakedOpDispatcher.cpp \ BakedOpRenderer.cpp \ BakedOpState.cpp \ - OpReorderer.cpp \ + FrameReorderer.cpp \ + LayerReorderer.cpp \ RecordingCanvas.cpp hwui_cflags += -DHWUI_NEW_OPS @@ -236,8 +237,8 @@ LOCAL_SRC_FILES += \ ifeq (true, $(HWUI_NEW_OPS)) LOCAL_SRC_FILES += \ tests/unit/BakedOpStateTests.cpp \ - tests/unit/RecordingCanvasTests.cpp \ - tests/unit/OpReordererTests.cpp + tests/unit/FrameReordererTests.cpp \ + tests/unit/RecordingCanvasTests.cpp endif include $(BUILD_NATIVE_TEST) @@ -298,7 +299,7 @@ LOCAL_SRC_FILES += \ ifeq (true, $(HWUI_NEW_OPS)) LOCAL_SRC_FILES += \ - tests/microbench/OpReordererBench.cpp + tests/microbench/FrameReordererBench.cpp endif include $(BUILD_EXECUTABLE) diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index 195d235fc7c1..23aca899a485 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -338,8 +338,8 @@ static void renderConvexPath(BakedOpRenderer& renderer, const BakedOpState& stat static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state, PathTexture& texture, const RecordedOp& op) { Rect dest(texture.width, texture.height); - dest.translate(texture.left + op.unmappedBounds.left - texture.offset, - texture.top + op.unmappedBounds.top - texture.offset); + dest.translate(texture.left - texture.offset, + texture.top - texture.offset); Glop glop; GlopBuilder(renderer.renderState(), renderer.caches(), &glop) .setRoundRectClipState(state.roundRectClipState) diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp index b9c13e6cf847..c1f19a341956 100644 --- a/libs/hwui/BakedOpRenderer.cpp +++ b/libs/hwui/BakedOpRenderer.cpp @@ -201,6 +201,7 @@ void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices, } void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) { + LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::RectangleList, "can't rectlist clip without rectlist"); auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList; int quadCount = rectList.getTransformedRectanglesCount(); std::vector<Vertex> rectangleVertices; @@ -234,6 +235,7 @@ void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) { } void BakedOpRenderer::setupStencilRegion(const ClipBase* clip) { + LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::Region, "can't region clip without region"); auto&& region = reinterpret_cast<const ClipRegion*>(clip)->region; std::vector<Vertex> regionVertices; diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp index f1cc846593db..f0406fa13a3d 100644 --- a/libs/hwui/BakedOpState.cpp +++ b/libs/hwui/BakedOpState.cpp @@ -48,10 +48,10 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s const Rect& clipRect = clipState->rect; if (CC_UNLIKELY(clipRect.isEmpty() || !clippedBounds.intersects(clipRect))) { // Rejected based on either empty clip, or bounds not intersecting with clip - if (clipState) { - allocator.rewindIfLastAlloc(clipState); - clipState = nullptr; - } + + // Note: we could rewind the clipState object in situations where the clipRect is empty, + // but *only* if the caching logic within ClipArea was aware of the rewind. + clipState = nullptr; clippedBounds.setEmpty(); } else { // Not rejected! compute true clippedBounds and clipSideFlags diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h index 5c7b43f5a034..3db28c982469 100644 --- a/libs/hwui/BakedOpState.h +++ b/libs/hwui/BakedOpState.h @@ -99,6 +99,7 @@ class BakedOpState { public: static BakedOpState* tryConstruct(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp) { + if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; BakedOpState* bakedState = new (allocator) BakedOpState( allocator, snapshot, recordedOp, false); if (bakedState->computedState.clippedBounds.isEmpty()) { @@ -118,6 +119,7 @@ public: static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) { + if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined) ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style) : true; @@ -126,6 +128,7 @@ public: allocator, snapshot, recordedOp, expandForStroke); if (bakedState->computedState.clippedBounds.isEmpty()) { // bounds are empty, so op is rejected + // NOTE: this won't succeed if a clip was allocated allocator.rewindIfLastAlloc(bakedState); return nullptr; } @@ -134,7 +137,7 @@ public: static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr) { - if (snapshot.getRenderTargetClip().isEmpty()) return nullptr; + if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; // clip isn't empty, so construct the op return new (allocator) BakedOpState(allocator, snapshot, shadowOpPtr); diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/FrameReorderer.cpp index cff4f3c47d60..4bfc0b413c56 100644 --- a/libs/hwui/OpReorderer.cpp +++ b/libs/hwui/FrameReorderer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "OpReorderer.h" +#include "FrameReorderer.h" #include "LayerUpdateQueue.h" #include "RenderNode.h" @@ -30,343 +30,7 @@ namespace android { namespace uirenderer { -class BatchBase { -public: - BatchBase(batchid_t batchId, BakedOpState* op, bool merging) - : mBatchId(batchId) - , mMerging(merging) { - mBounds = op->computedState.clippedBounds; - mOps.push_back(op); - } - - bool intersects(const Rect& rect) const { - if (!rect.intersects(mBounds)) return false; - - for (const BakedOpState* op : mOps) { - if (rect.intersects(op->computedState.clippedBounds)) { - return true; - } - } - return false; - } - - batchid_t getBatchId() const { return mBatchId; } - bool isMerging() const { return mMerging; } - - const std::vector<BakedOpState*>& getOps() const { return mOps; } - - void dump() const { - ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING, - this, mBatchId, mMerging, mOps.size(), RECT_ARGS(mBounds)); - } -protected: - batchid_t mBatchId; - Rect mBounds; - std::vector<BakedOpState*> mOps; - bool mMerging; -}; - -class OpBatch : public BatchBase { -public: - static void* operator new(size_t size, LinearAllocator& allocator) { - return allocator.alloc(size); - } - - OpBatch(batchid_t batchId, BakedOpState* op) - : BatchBase(batchId, op, false) { - } - - void batchOp(BakedOpState* op) { - mBounds.unionWith(op->computedState.clippedBounds); - mOps.push_back(op); - } -}; - -class MergingOpBatch : public BatchBase { -public: - static void* operator new(size_t size, LinearAllocator& allocator) { - return allocator.alloc(size); - } - - MergingOpBatch(batchid_t batchId, BakedOpState* op) - : BatchBase(batchId, op, true) - , mClipSideFlags(op->computedState.clipSideFlags) { - } - - /* - * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds - * and clip side flags. Positive bounds delta means new bounds fit in old. - */ - static inline bool checkSide(const int currentFlags, const int newFlags, const int side, - float boundsDelta) { - bool currentClipExists = currentFlags & side; - bool newClipExists = newFlags & side; - - // if current is clipped, we must be able to fit new bounds in current - if (boundsDelta > 0 && currentClipExists) return false; - - // if new is clipped, we must be able to fit current bounds in new - if (boundsDelta < 0 && newClipExists) return false; - - return true; - } - - static bool paintIsDefault(const SkPaint& paint) { - return paint.getAlpha() == 255 - && paint.getColorFilter() == nullptr - && paint.getShader() == nullptr; - } - - static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) { - return a.getAlpha() == b.getAlpha() - && a.getColorFilter() == b.getColorFilter() - && a.getShader() == b.getShader(); - } - - /* - * Checks if a (mergeable) op can be merged into this batch - * - * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is - * important to consider all paint attributes used in the draw calls in deciding both a) if an - * op tries to merge at all, and b) if the op can merge with another set of ops - * - * False positives can lead to information from the paints of subsequent merged operations being - * dropped, so we make simplifying qualifications on the ops that can merge, per op type. - */ - bool canMergeWith(BakedOpState* op) const { - bool isTextBatch = getBatchId() == OpBatchType::Text - || getBatchId() == OpBatchType::ColorText; - - // Overlapping other operations is only allowed for text without shadow. For other ops, - // multiDraw isn't guaranteed to overdraw correctly - if (!isTextBatch || PaintUtils::hasTextShadow(op->op->paint)) { - if (intersects(op->computedState.clippedBounds)) return false; - } - - const BakedOpState* lhs = op; - const BakedOpState* rhs = mOps[0]; - - if (!MathUtils::areEqual(lhs->alpha, rhs->alpha)) return false; - - // Identical round rect clip state means both ops will clip in the same way, or not at all. - // As the state objects are const, we can compare their pointers to determine mergeability - if (lhs->roundRectClipState != rhs->roundRectClipState) return false; - if (lhs->projectionPathMask != rhs->projectionPathMask) return false; - - /* Clipping compatibility check - * - * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its - * clip for that side. - */ - const int currentFlags = mClipSideFlags; - const int newFlags = op->computedState.clipSideFlags; - if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) { - const Rect& opBounds = op->computedState.clippedBounds; - float boundsDelta = mBounds.left - opBounds.left; - if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false; - boundsDelta = mBounds.top - opBounds.top; - if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false; - - // right and bottom delta calculation reversed to account for direction - boundsDelta = opBounds.right - mBounds.right; - if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false; - boundsDelta = opBounds.bottom - mBounds.bottom; - if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false; - } - - const SkPaint* newPaint = op->op->paint; - const SkPaint* oldPaint = mOps[0]->op->paint; - - if (newPaint == oldPaint) { - // if paints are equal, then modifiers + paint attribs don't need to be compared - return true; - } else if (newPaint && !oldPaint) { - return paintIsDefault(*newPaint); - } else if (!newPaint && oldPaint) { - return paintIsDefault(*oldPaint); - } - return paintsAreEquivalent(*newPaint, *oldPaint); - } - - void mergeOp(BakedOpState* op) { - mBounds.unionWith(op->computedState.clippedBounds); - mOps.push_back(op); - - // Because a new op must have passed canMergeWith(), we know it's passed the clipping compat - // check, and doesn't extend past a side of the clip that's in use by the merged batch. - // Therefore it's safe to simply always merge flags, and use the bounds as the clip rect. - mClipSideFlags |= op->computedState.clipSideFlags; - } - - int getClipSideFlags() const { return mClipSideFlags; } - const Rect& getClipRect() const { return mBounds; } - -private: - int mClipSideFlags; -}; - -OpReorderer::LayerReorderer::LayerReorderer(uint32_t width, uint32_t height, - const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode) - : width(width) - , height(height) - , repaintRect(repaintRect) - , offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr) - , beginLayerOp(beginLayerOp) - , renderNode(renderNode) - , viewportClip(Rect(width, height)) {} - -// iterate back toward target to see if anything drawn since should overlap the new op -// if no target, merging ops still iterate to find similar batch to insert after -void OpReorderer::LayerReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds, - BatchBase** targetBatch, size_t* insertBatchIndex) const { - for (int i = mBatches.size() - 1; i >= 0; i--) { - BatchBase* overBatch = mBatches[i]; - - if (overBatch == *targetBatch) break; - - // TODO: also consider shader shared between batch types - if (batchId == overBatch->getBatchId()) { - *insertBatchIndex = i + 1; - if (!*targetBatch) break; // found insert position, quit - } - - if (overBatch->intersects(clippedBounds)) { - // NOTE: it may be possible to optimize for special cases where two operations - // of the same batch/paint could swap order, such as with a non-mergeable - // (clipped) and a mergeable text operation - *targetBatch = nullptr; - break; - } - } -} - -void OpReorderer::LayerReorderer::deferLayerClear(const Rect& rect) { - mClearRects.push_back(rect); -} - -void OpReorderer::LayerReorderer::flushLayerClears(LinearAllocator& allocator) { - if (CC_UNLIKELY(!mClearRects.empty())) { - const int vertCount = mClearRects.size() * 4; - // put the verts in the frame allocator, since - // 1) SimpleRectsOps needs verts, not rects - // 2) even if mClearRects stored verts, std::vectors will move their contents - Vertex* const verts = (Vertex*) allocator.alloc(vertCount * sizeof(Vertex)); - - Vertex* currentVert = verts; - Rect bounds = mClearRects[0]; - for (auto&& rect : mClearRects) { - bounds.unionWith(rect); - Vertex::set(currentVert++, rect.left, rect.top); - Vertex::set(currentVert++, rect.right, rect.top); - Vertex::set(currentVert++, rect.left, rect.bottom); - Vertex::set(currentVert++, rect.right, rect.bottom); - } - mClearRects.clear(); // discard rects before drawing so this method isn't reentrant - - // One or more unclipped saveLayers have been enqueued, with deferred clears. - // Flush all of these clears with a single draw - SkPaint* paint = allocator.create<SkPaint>(); - paint->setXfermodeMode(SkXfermode::kClear_Mode); - SimpleRectsOp* op = new (allocator) SimpleRectsOp(bounds, - Matrix4::identity(), nullptr, paint, - verts, vertCount); - BakedOpState* bakedState = BakedOpState::directConstruct(allocator, - &viewportClip, bounds, *op); - - - deferUnmergeableOp(allocator, bakedState, OpBatchType::Vertices); - } -} - -void OpReorderer::LayerReorderer::deferUnmergeableOp(LinearAllocator& allocator, - BakedOpState* op, batchid_t batchId) { - if (batchId != OpBatchType::CopyToLayer) { - // if first op after one or more unclipped saveLayers, flush the layer clears - flushLayerClears(allocator); - } - - OpBatch* targetBatch = mBatchLookup[batchId]; - - size_t insertBatchIndex = mBatches.size(); - if (targetBatch) { - locateInsertIndex(batchId, op->computedState.clippedBounds, - (BatchBase**)(&targetBatch), &insertBatchIndex); - } - - if (targetBatch) { - targetBatch->batchOp(op); - } else { - // new non-merging batch - targetBatch = new (allocator) OpBatch(batchId, op); - mBatchLookup[batchId] = targetBatch; - mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); - } -} - -void OpReorderer::LayerReorderer::deferMergeableOp(LinearAllocator& allocator, - BakedOpState* op, batchid_t batchId, mergeid_t mergeId) { - if (batchId != OpBatchType::CopyToLayer) { - // if first op after one or more unclipped saveLayers, flush the layer clears - flushLayerClears(allocator); - } - MergingOpBatch* targetBatch = nullptr; - - // Try to merge with any existing batch with same mergeId - auto getResult = mMergingBatchLookup[batchId].find(mergeId); - if (getResult != mMergingBatchLookup[batchId].end()) { - targetBatch = getResult->second; - if (!targetBatch->canMergeWith(op)) { - targetBatch = nullptr; - } - } - - size_t insertBatchIndex = mBatches.size(); - locateInsertIndex(batchId, op->computedState.clippedBounds, - (BatchBase**)(&targetBatch), &insertBatchIndex); - - if (targetBatch) { - targetBatch->mergeOp(op); - } else { - // new merging batch - targetBatch = new (allocator) MergingOpBatch(batchId, op); - mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch)); - - mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); - } -} - -void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, - BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const { - ATRACE_NAME("flush drawing commands"); - for (const BatchBase* batch : mBatches) { - size_t size = batch->getOps().size(); - if (size > 1 && batch->isMerging()) { - int opId = batch->getOps()[0]->op->opId; - const MergingOpBatch* mergingBatch = static_cast<const MergingOpBatch*>(batch); - MergedBakedOpList data = { - batch->getOps().data(), - size, - mergingBatch->getClipSideFlags(), - mergingBatch->getClipRect() - }; - mergedReceivers[opId](arg, data); - } else { - for (const BakedOpState* op : batch->getOps()) { - unmergedReceivers[op->op->opId](arg, *op); - } - } - } -} - -void OpReorderer::LayerReorderer::dump() const { - ALOGD("LayerReorderer %p, %ux%u buffer %p, blo %p, rn %p", - this, width, height, offscreenBuffer, beginLayerOp, renderNode); - for (const BatchBase* batch : mBatches) { - batch->dump(); - } -} - -OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, +FrameReorderer::FrameReorderer(const LayerUpdateQueue& layers, const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight, const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter) : mCanvasState(*this) { @@ -413,11 +77,11 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, } } -void OpReorderer::onViewportInitialized() {} +void FrameReorderer::onViewportInitialized() {} -void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} +void FrameReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} -void OpReorderer::deferNodePropsAndOps(RenderNode& node) { +void FrameReorderer::deferNodePropsAndOps(RenderNode& node) { const RenderProperties& properties = node.properties(); const Outline& outline = properties.getOutline(); if (properties.getAlpha() <= 0 @@ -549,7 +213,7 @@ static size_t findNonNegativeIndex(const V& zTranslatedNodes) { } template <typename V> -void OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) { +void FrameReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) { const int size = zTranslatedNodes.size(); if (size == 0 || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f) @@ -599,7 +263,7 @@ void OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedN } } -void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) { +void FrameReorderer::deferShadow(const RenderNodeOp& casterNodeOp) { auto& node = *casterNodeOp.renderNode; auto& properties = node.properties(); @@ -655,7 +319,7 @@ void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) { } } -void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { +void FrameReorderer::deferProjectedChildren(const RenderNode& renderNode) { const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath(); int count = mCanvasState.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); @@ -688,15 +352,15 @@ void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { } /** - * Used to define a list of lambdas referencing private OpReorderer::onXX::defer() methods. + * Used to define a list of lambdas referencing private FrameReorderer::onXX::defer() methods. * * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. - * E.g. a BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&) + * E.g. a BitmapOp op then would be dispatched to FrameReorderer::onBitmapOp(const BitmapOp&) */ #define OP_RECEIVER(Type) \ - [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); }, -void OpReorderer::deferNodeOps(const RenderNode& renderNode) { - typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op); + [](FrameReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); }, +void FrameReorderer::deferNodeOps(const RenderNode& renderNode) { + typedef void (*OpDispatcher) (FrameReorderer& reorderer, const RecordedOp& op); static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER); // can't be null, since DL=null node rejection happens before deferNodePropsAndOps @@ -720,7 +384,7 @@ void OpReorderer::deferNodeOps(const RenderNode& renderNode) { } } -void OpReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) { +void FrameReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) { if (op.renderNode->nothingToDraw()) return; int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); @@ -735,7 +399,7 @@ void OpReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) { mCanvasState.restoreToCount(count); } -void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { +void FrameReorderer::deferRenderNodeOp(const RenderNodeOp& op) { if (!op.skipInOrderDraw) { deferRenderNodeOpImpl(op); } @@ -745,7 +409,7 @@ void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { * Defers an unmergeable, strokeable op, accounting correctly * for paint's style on the bounds being computed. */ -void OpReorderer::deferStrokeableOp(const RecordedOp& op, batchid_t batchId, +void FrameReorderer::deferStrokeableOp(const RecordedOp& op, batchid_t batchId, BakedOpState::StrokeBehavior strokeBehavior) { // Note: here we account for stroke when baking the op BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( @@ -767,7 +431,7 @@ static batchid_t tessBatchId(const RecordedOp& op) { : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices); } -void OpReorderer::deferArcOp(const ArcOp& op) { +void FrameReorderer::deferArcOp(const ArcOp& op) { deferStrokeableOp(op, tessBatchId(op)); } @@ -776,7 +440,7 @@ static bool hasMergeableClip(const BakedOpState& state) { || state.computedState.clipState->mode == ClipMode::Rectangle; } -void OpReorderer::deferBitmapOp(const BitmapOp& op) { +void FrameReorderer::deferBitmapOp(const BitmapOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected @@ -796,19 +460,19 @@ void OpReorderer::deferBitmapOp(const BitmapOp& op) { } } -void OpReorderer::deferBitmapMeshOp(const BitmapMeshOp& op) { +void FrameReorderer::deferBitmapMeshOp(const BitmapMeshOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); } -void OpReorderer::deferBitmapRectOp(const BitmapRectOp& op) { +void FrameReorderer::deferBitmapRectOp(const BitmapRectOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); } -void OpReorderer::deferCirclePropsOp(const CirclePropsOp& op) { +void FrameReorderer::deferCirclePropsOp(const CirclePropsOp& op) { // allocate a temporary oval op (with mAllocator, so it persists until render), so the // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. float x = *(op.x); @@ -823,22 +487,22 @@ void OpReorderer::deferCirclePropsOp(const CirclePropsOp& op) { deferOvalOp(*resolvedOp); } -void OpReorderer::deferFunctorOp(const FunctorOp& op) { +void FrameReorderer::deferFunctorOp(const FunctorOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor); } -void OpReorderer::deferLinesOp(const LinesOp& op) { +void FrameReorderer::deferLinesOp(const LinesOp& op) { batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); } -void OpReorderer::deferOvalOp(const OvalOp& op) { +void FrameReorderer::deferOvalOp(const OvalOp& op) { deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::deferPatchOp(const PatchOp& op) { +void FrameReorderer::deferPatchOp(const PatchOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected @@ -856,24 +520,24 @@ void OpReorderer::deferPatchOp(const PatchOp& op) { } } -void OpReorderer::deferPathOp(const PathOp& op) { +void FrameReorderer::deferPathOp(const PathOp& op) { deferStrokeableOp(op, OpBatchType::Bitmap); } -void OpReorderer::deferPointsOp(const PointsOp& op) { +void FrameReorderer::deferPointsOp(const PointsOp& op) { batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); } -void OpReorderer::deferRectOp(const RectOp& op) { +void FrameReorderer::deferRectOp(const RectOp& op) { deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::deferRoundRectOp(const RoundRectOp& op) { +void FrameReorderer::deferRoundRectOp(const RoundRectOp& op) { deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) { +void FrameReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) { // allocate a temporary round rect op (with mAllocator, so it persists until render), so the // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp( @@ -884,7 +548,7 @@ void OpReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) { deferRoundRectOp(*resolvedOp); } -void OpReorderer::deferSimpleRectsOp(const SimpleRectsOp& op) { +void FrameReorderer::deferSimpleRectsOp(const SimpleRectsOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); @@ -895,7 +559,7 @@ static batchid_t textBatchId(const SkPaint& paint) { return paint.getColor() == SK_ColorBLACK ? OpBatchType::Text : OpBatchType::ColorText; } -void OpReorderer::deferTextOp(const TextOp& op) { +void FrameReorderer::deferTextOp(const TextOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected @@ -910,19 +574,19 @@ void OpReorderer::deferTextOp(const TextOp& op) { } } -void OpReorderer::deferTextOnPathOp(const TextOnPathOp& op) { +void FrameReorderer::deferTextOnPathOp(const TextOnPathOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint))); } -void OpReorderer::deferTextureLayerOp(const TextureLayerOp& op) { +void FrameReorderer::deferTextureLayerOp(const TextureLayerOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer); } -void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, +void FrameReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX, float contentTranslateY, const Rect& repaintRect, const Vector3& lightCenter, @@ -941,7 +605,7 @@ void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, mLayerReorderers.emplace_back(layerWidth, layerHeight, repaintRect, beginLayerOp, renderNode); } -void OpReorderer::restoreForLayer() { +void FrameReorderer::restoreForLayer() { // restore canvas, and pop finished layer off of the stack mCanvasState.restore(); mLayerStack.pop_back(); @@ -949,7 +613,7 @@ void OpReorderer::restoreForLayer() { // TODO: defer time rejection (when bounds become empty) + tests // Option - just skip layers with no bounds at playback + defer? -void OpReorderer::deferBeginLayerOp(const BeginLayerOp& op) { +void FrameReorderer::deferBeginLayerOp(const BeginLayerOp& op) { uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth(); uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight(); @@ -994,7 +658,7 @@ void OpReorderer::deferBeginLayerOp(const BeginLayerOp& op) { &op, nullptr); } -void OpReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) { +void FrameReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) { const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp; int finishedLayerIndex = mLayerStack.back(); @@ -1022,7 +686,7 @@ void OpReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) { } } -void OpReorderer::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) { +void FrameReorderer::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) { Matrix4 boundsTransform(*(mCanvasState.currentSnapshot()->transform)); boundsTransform.multiply(op.localMatrix); @@ -1057,7 +721,7 @@ void OpReorderer::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) { currentLayer().activeUnclippedSaveLayers.push_back(bakedState); } -void OpReorderer::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignored */) { +void FrameReorderer::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignored */) { LOG_ALWAYS_FATAL_IF(currentLayer().activeUnclippedSaveLayers.empty(), "no layer to end!"); BakedOpState* copyFromLayerOp = currentLayer().activeUnclippedSaveLayers.back(); diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/FrameReorderer.h index 8d9d90be057c..562e6a1a3d37 100644 --- a/libs/hwui/OpReorderer.h +++ b/libs/hwui/FrameReorderer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 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. @@ -14,12 +14,12 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_OP_REORDERER_H -#define ANDROID_HWUI_OP_REORDERER_H +#pragma once #include "BakedOpState.h" #include "CanvasState.h" #include "DisplayList.h" +#include "LayerReorderer.h" #include "RecordedOp.h" #include <vector> @@ -31,114 +31,34 @@ namespace android { namespace uirenderer { class BakedOpState; -class BatchBase; class LayerUpdateQueue; -class MergingOpBatch; class OffscreenBuffer; -class OpBatch; class Rect; -typedef int batchid_t; -typedef const void* mergeid_t; - -namespace OpBatchType { - enum { - Bitmap, - MergedPatch, - AlphaVertices, - Vertices, - AlphaMaskTexture, - Text, - ColorText, - Shadow, - TextureLayer, - Functor, - CopyToLayer, - CopyFromLayer, - - Count // must be last - }; -} - -class OpReorderer : public CanvasStateClient { - typedef void (*BakedOpReceiver)(void*, const BakedOpState&); - typedef void (*MergedOpReceiver)(void*, const MergedBakedOpList& opList); - - /** - * Stores the deferred render operations and state used to compute ordering - * for a single FBO/layer. - */ - class LayerReorderer { - public: - // Create LayerReorderer for Fbo0 - LayerReorderer(uint32_t width, uint32_t height, const Rect& repaintRect) - : LayerReorderer(width, height, repaintRect, nullptr, nullptr) {}; - - // Create LayerReorderer for an offscreen layer, where beginLayerOp is present for a - // saveLayer, renderNode is present for a HW layer. - LayerReorderer(uint32_t width, uint32_t height, - const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode); - - // iterate back toward target to see if anything drawn since should overlap the new op - // if no target, merging ops still iterate to find similar batch to insert after - void locateInsertIndex(int batchId, const Rect& clippedBounds, - BatchBase** targetBatch, size_t* insertBatchIndex) const; - - void deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId); - - // insertion point of a new batch, will hopefully be immediately after similar batch - // (generally, should be similar shader) - void deferMergeableOp(LinearAllocator& allocator, - BakedOpState* op, batchid_t batchId, mergeid_t mergeId); - - void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers, MergedOpReceiver*) const; - - void deferLayerClear(const Rect& dstRect); - - bool empty() const { - return mBatches.empty(); - } - - void clear() { - mBatches.clear(); - } - - void dump() const; - - const uint32_t width; - const uint32_t height; - const Rect repaintRect; - OffscreenBuffer* offscreenBuffer; - const BeginLayerOp* beginLayerOp; - const RenderNode* renderNode; - const ClipRect viewportClip; - - // list of deferred CopyFromLayer ops, to be deferred upon encountering EndUnclippedLayerOps - std::vector<BakedOpState*> activeUnclippedSaveLayers; - private: - void flushLayerClears(LinearAllocator& allocator); - - std::vector<BatchBase*> mBatches; - - /** - * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen - * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not - * collide, which avoids the need to resolve mergeid collisions. - */ - std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatchLookup[OpBatchType::Count]; - - // Maps batch ids to the most recent *non-merging* batch of that id - OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr }; - - std::vector<Rect> mClearRects; - }; - +/** + * Traverses all of the drawing commands from the layers and RenderNodes passed into it, preparing + * them to be rendered. + * + * Resolves final drawing state for each operation (including clip, alpha and matrix), and then + * reorder and merge each op as it is resolved for drawing efficiency. Each layer of content (either + * from the LayerUpdateQueue, or temporary layers created by saveLayer operations in the + * draw stream) will create different reorder contexts, each in its own LayerReorderer. + * + * Then the prepared or 'baked' drawing commands can be issued by calling the templated + * replayBakedOps() function, which will dispatch them (including any created merged op collections) + * to a Dispatcher and Renderer. See BakedOpDispatcher for how these baked drawing operations are + * resolved into Glops and rendered via BakedOpRenderer. + * + * This class is also the authoritative source for traversing RenderNodes, both for standard op + * traversal within a DisplayList, and for out of order RenderNode traversal for Z and projection. + */ +class FrameReorderer : public CanvasStateClient { public: - OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, + FrameReorderer(const LayerUpdateQueue& layers, const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight, const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter); - virtual ~OpReorderer() {} + virtual ~FrameReorderer() {} /** * replayBakedOps() is templated based on what class will receive ops being replayed. @@ -253,7 +173,7 @@ private: BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined); /** - * Declares all OpReorderer::deferXXXXOp() methods for every RecordedOp type. + * Declares all FrameReorderer::deferXXXXOp() methods for every RecordedOp type. * * These private methods are called from within deferImpl to defer each individual op * type differently. @@ -287,5 +207,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_OP_REORDERER_H diff --git a/libs/hwui/LayerReorderer.cpp b/libs/hwui/LayerReorderer.cpp new file mode 100644 index 000000000000..9a17e9349e56 --- /dev/null +++ b/libs/hwui/LayerReorderer.cpp @@ -0,0 +1,367 @@ +/* + * 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. + */ + +#include "LayerReorderer.h" + +#include "BakedOpState.h" +#include "RenderNode.h" +#include "utils/PaintUtils.h" +#include "utils/TraceUtils.h" + +#include <utils/TypeHelpers.h> + +namespace android { +namespace uirenderer { + +class BatchBase { +public: + BatchBase(batchid_t batchId, BakedOpState* op, bool merging) + : mBatchId(batchId) + , mMerging(merging) { + mBounds = op->computedState.clippedBounds; + mOps.push_back(op); + } + + bool intersects(const Rect& rect) const { + if (!rect.intersects(mBounds)) return false; + + for (const BakedOpState* op : mOps) { + if (rect.intersects(op->computedState.clippedBounds)) { + return true; + } + } + return false; + } + + batchid_t getBatchId() const { return mBatchId; } + bool isMerging() const { return mMerging; } + + const std::vector<BakedOpState*>& getOps() const { return mOps; } + + void dump() const { + ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING, + this, mBatchId, mMerging, mOps.size(), RECT_ARGS(mBounds)); + } +protected: + batchid_t mBatchId; + Rect mBounds; + std::vector<BakedOpState*> mOps; + bool mMerging; +}; + +class OpBatch : public BatchBase { +public: + static void* operator new(size_t size, LinearAllocator& allocator) { + return allocator.alloc(size); + } + + OpBatch(batchid_t batchId, BakedOpState* op) + : BatchBase(batchId, op, false) { + } + + void batchOp(BakedOpState* op) { + mBounds.unionWith(op->computedState.clippedBounds); + mOps.push_back(op); + } +}; + +class MergingOpBatch : public BatchBase { +public: + static void* operator new(size_t size, LinearAllocator& allocator) { + return allocator.alloc(size); + } + + MergingOpBatch(batchid_t batchId, BakedOpState* op) + : BatchBase(batchId, op, true) + , mClipSideFlags(op->computedState.clipSideFlags) { + } + + /* + * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds + * and clip side flags. Positive bounds delta means new bounds fit in old. + */ + static inline bool checkSide(const int currentFlags, const int newFlags, const int side, + float boundsDelta) { + bool currentClipExists = currentFlags & side; + bool newClipExists = newFlags & side; + + // if current is clipped, we must be able to fit new bounds in current + if (boundsDelta > 0 && currentClipExists) return false; + + // if new is clipped, we must be able to fit current bounds in new + if (boundsDelta < 0 && newClipExists) return false; + + return true; + } + + static bool paintIsDefault(const SkPaint& paint) { + return paint.getAlpha() == 255 + && paint.getColorFilter() == nullptr + && paint.getShader() == nullptr; + } + + static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) { + // Note: don't check color, since all currently mergeable ops can merge across colors + return a.getAlpha() == b.getAlpha() + && a.getColorFilter() == b.getColorFilter() + && a.getShader() == b.getShader(); + } + + /* + * Checks if a (mergeable) op can be merged into this batch + * + * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is + * important to consider all paint attributes used in the draw calls in deciding both a) if an + * op tries to merge at all, and b) if the op can merge with another set of ops + * + * False positives can lead to information from the paints of subsequent merged operations being + * dropped, so we make simplifying qualifications on the ops that can merge, per op type. + */ + bool canMergeWith(BakedOpState* op) const { + bool isTextBatch = getBatchId() == OpBatchType::Text + || getBatchId() == OpBatchType::ColorText; + + // Overlapping other operations is only allowed for text without shadow. For other ops, + // multiDraw isn't guaranteed to overdraw correctly + if (!isTextBatch || PaintUtils::hasTextShadow(op->op->paint)) { + if (intersects(op->computedState.clippedBounds)) return false; + } + + const BakedOpState* lhs = op; + const BakedOpState* rhs = mOps[0]; + + if (!MathUtils::areEqual(lhs->alpha, rhs->alpha)) return false; + + // Identical round rect clip state means both ops will clip in the same way, or not at all. + // As the state objects are const, we can compare their pointers to determine mergeability + if (lhs->roundRectClipState != rhs->roundRectClipState) return false; + if (lhs->projectionPathMask != rhs->projectionPathMask) return false; + + /* Clipping compatibility check + * + * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its + * clip for that side. + */ + const int currentFlags = mClipSideFlags; + const int newFlags = op->computedState.clipSideFlags; + if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) { + const Rect& opBounds = op->computedState.clippedBounds; + float boundsDelta = mBounds.left - opBounds.left; + if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false; + boundsDelta = mBounds.top - opBounds.top; + if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false; + + // right and bottom delta calculation reversed to account for direction + boundsDelta = opBounds.right - mBounds.right; + if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false; + boundsDelta = opBounds.bottom - mBounds.bottom; + if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false; + } + + const SkPaint* newPaint = op->op->paint; + const SkPaint* oldPaint = mOps[0]->op->paint; + + if (newPaint == oldPaint) { + // if paints are equal, then modifiers + paint attribs don't need to be compared + return true; + } else if (newPaint && !oldPaint) { + return paintIsDefault(*newPaint); + } else if (!newPaint && oldPaint) { + return paintIsDefault(*oldPaint); + } + return paintsAreEquivalent(*newPaint, *oldPaint); + } + + void mergeOp(BakedOpState* op) { + mBounds.unionWith(op->computedState.clippedBounds); + mOps.push_back(op); + + // Because a new op must have passed canMergeWith(), we know it's passed the clipping compat + // check, and doesn't extend past a side of the clip that's in use by the merged batch. + // Therefore it's safe to simply always merge flags, and use the bounds as the clip rect. + mClipSideFlags |= op->computedState.clipSideFlags; + } + + int getClipSideFlags() const { return mClipSideFlags; } + const Rect& getClipRect() const { return mBounds; } + +private: + int mClipSideFlags; +}; + +LayerReorderer::LayerReorderer(uint32_t width, uint32_t height, + const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode) + : width(width) + , height(height) + , repaintRect(repaintRect) + , offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr) + , beginLayerOp(beginLayerOp) + , renderNode(renderNode) + , viewportClip(Rect(width, height)) {} + +// iterate back toward target to see if anything drawn since should overlap the new op +// if no target, merging ops still iterate to find similar batch to insert after +void LayerReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds, + BatchBase** targetBatch, size_t* insertBatchIndex) const { + for (int i = mBatches.size() - 1; i >= 0; i--) { + BatchBase* overBatch = mBatches[i]; + + if (overBatch == *targetBatch) break; + + // TODO: also consider shader shared between batch types + if (batchId == overBatch->getBatchId()) { + *insertBatchIndex = i + 1; + if (!*targetBatch) break; // found insert position, quit + } + + if (overBatch->intersects(clippedBounds)) { + // NOTE: it may be possible to optimize for special cases where two operations + // of the same batch/paint could swap order, such as with a non-mergeable + // (clipped) and a mergeable text operation + *targetBatch = nullptr; + break; + } + } +} + +void LayerReorderer::deferLayerClear(const Rect& rect) { + mClearRects.push_back(rect); +} + +void LayerReorderer::flushLayerClears(LinearAllocator& allocator) { + if (CC_UNLIKELY(!mClearRects.empty())) { + const int vertCount = mClearRects.size() * 4; + // put the verts in the frame allocator, since + // 1) SimpleRectsOps needs verts, not rects + // 2) even if mClearRects stored verts, std::vectors will move their contents + Vertex* const verts = (Vertex*) allocator.alloc(vertCount * sizeof(Vertex)); + + Vertex* currentVert = verts; + Rect bounds = mClearRects[0]; + for (auto&& rect : mClearRects) { + bounds.unionWith(rect); + Vertex::set(currentVert++, rect.left, rect.top); + Vertex::set(currentVert++, rect.right, rect.top); + Vertex::set(currentVert++, rect.left, rect.bottom); + Vertex::set(currentVert++, rect.right, rect.bottom); + } + mClearRects.clear(); // discard rects before drawing so this method isn't reentrant + + // One or more unclipped saveLayers have been enqueued, with deferred clears. + // Flush all of these clears with a single draw + SkPaint* paint = allocator.create<SkPaint>(); + paint->setXfermodeMode(SkXfermode::kClear_Mode); + SimpleRectsOp* op = new (allocator) SimpleRectsOp(bounds, + Matrix4::identity(), nullptr, paint, + verts, vertCount); + BakedOpState* bakedState = BakedOpState::directConstruct(allocator, + &viewportClip, bounds, *op); + + + deferUnmergeableOp(allocator, bakedState, OpBatchType::Vertices); + } +} + +void LayerReorderer::deferUnmergeableOp(LinearAllocator& allocator, + BakedOpState* op, batchid_t batchId) { + if (batchId != OpBatchType::CopyToLayer) { + // if first op after one or more unclipped saveLayers, flush the layer clears + flushLayerClears(allocator); + } + + OpBatch* targetBatch = mBatchLookup[batchId]; + + size_t insertBatchIndex = mBatches.size(); + if (targetBatch) { + locateInsertIndex(batchId, op->computedState.clippedBounds, + (BatchBase**)(&targetBatch), &insertBatchIndex); + } + + if (targetBatch) { + targetBatch->batchOp(op); + } else { + // new non-merging batch + targetBatch = new (allocator) OpBatch(batchId, op); + mBatchLookup[batchId] = targetBatch; + mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); + } +} + +void LayerReorderer::deferMergeableOp(LinearAllocator& allocator, + BakedOpState* op, batchid_t batchId, mergeid_t mergeId) { + if (batchId != OpBatchType::CopyToLayer) { + // if first op after one or more unclipped saveLayers, flush the layer clears + flushLayerClears(allocator); + } + MergingOpBatch* targetBatch = nullptr; + + // Try to merge with any existing batch with same mergeId + auto getResult = mMergingBatchLookup[batchId].find(mergeId); + if (getResult != mMergingBatchLookup[batchId].end()) { + targetBatch = getResult->second; + if (!targetBatch->canMergeWith(op)) { + targetBatch = nullptr; + } + } + + size_t insertBatchIndex = mBatches.size(); + locateInsertIndex(batchId, op->computedState.clippedBounds, + (BatchBase**)(&targetBatch), &insertBatchIndex); + + if (targetBatch) { + targetBatch->mergeOp(op); + } else { + // new merging batch + targetBatch = new (allocator) MergingOpBatch(batchId, op); + mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch)); + + mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); + } +} + +void LayerReorderer::replayBakedOpsImpl(void* arg, + BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const { + ATRACE_NAME("flush drawing commands"); + for (const BatchBase* batch : mBatches) { + size_t size = batch->getOps().size(); + if (size > 1 && batch->isMerging()) { + int opId = batch->getOps()[0]->op->opId; + const MergingOpBatch* mergingBatch = static_cast<const MergingOpBatch*>(batch); + MergedBakedOpList data = { + batch->getOps().data(), + size, + mergingBatch->getClipSideFlags(), + mergingBatch->getClipRect() + }; + mergedReceivers[opId](arg, data); + } else { + for (const BakedOpState* op : batch->getOps()) { + unmergedReceivers[op->op->opId](arg, *op); + } + } + } +} + +void LayerReorderer::dump() const { + ALOGD("LayerReorderer %p, %ux%u buffer %p, blo %p, rn %p", + this, width, height, offscreenBuffer, beginLayerOp, renderNode); + for (const BatchBase* batch : mBatches) { + batch->dump(); + } +} + +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/LayerReorderer.h b/libs/hwui/LayerReorderer.h new file mode 100644 index 000000000000..83cda812035d --- /dev/null +++ b/libs/hwui/LayerReorderer.h @@ -0,0 +1,135 @@ +/* + * 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. + */ + +#pragma once + +#include "ClipArea.h" +#include "Rect.h" + +#include <vector> +#include <unordered_map> + +struct SkRect; + +namespace android { +namespace uirenderer { + +class BakedOpState; +struct BeginLayerOp; +class BatchBase; +class LinearAllocator; +struct MergedBakedOpList; +class MergingOpBatch; +class OffscreenBuffer; +class OpBatch; +class RenderNode; + +typedef int batchid_t; +typedef const void* mergeid_t; + +namespace OpBatchType { + enum { + Bitmap, + MergedPatch, + AlphaVertices, + Vertices, + AlphaMaskTexture, + Text, + ColorText, + Shadow, + TextureLayer, + Functor, + CopyToLayer, + CopyFromLayer, + + Count // must be last + }; +} + +typedef void (*BakedOpReceiver)(void*, const BakedOpState&); +typedef void (*MergedOpReceiver)(void*, const MergedBakedOpList& opList); + +/** + * Stores the deferred render operations and state used to compute ordering + * for a single FBO/layer. + */ +class LayerReorderer { +public: + // Create LayerReorderer for Fbo0 + LayerReorderer(uint32_t width, uint32_t height, const Rect& repaintRect) + : LayerReorderer(width, height, repaintRect, nullptr, nullptr) {}; + + // Create LayerReorderer for an offscreen layer, where beginLayerOp is present for a + // saveLayer, renderNode is present for a HW layer. + LayerReorderer(uint32_t width, uint32_t height, + const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode); + + // iterate back toward target to see if anything drawn since should overlap the new op + // if no target, merging ops still iterate to find similar batch to insert after + void locateInsertIndex(int batchId, const Rect& clippedBounds, + BatchBase** targetBatch, size_t* insertBatchIndex) const; + + void deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId); + + // insertion point of a new batch, will hopefully be immediately after similar batch + // (generally, should be similar shader) + void deferMergeableOp(LinearAllocator& allocator, + BakedOpState* op, batchid_t batchId, mergeid_t mergeId); + + void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers, MergedOpReceiver*) const; + + void deferLayerClear(const Rect& dstRect); + + bool empty() const { + return mBatches.empty(); + } + + void clear() { + mBatches.clear(); + } + + void dump() const; + + const uint32_t width; + const uint32_t height; + const Rect repaintRect; + OffscreenBuffer* offscreenBuffer; + const BeginLayerOp* beginLayerOp; + const RenderNode* renderNode; + const ClipRect viewportClip; + + // list of deferred CopyFromLayer ops, to be deferred upon encountering EndUnclippedLayerOps + std::vector<BakedOpState*> activeUnclippedSaveLayers; +private: + void flushLayerClears(LinearAllocator& allocator); + + std::vector<BatchBase*> mBatches; + + /** + * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen + * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not + * collide, which avoids the need to resolve mergeid collisions. + */ + std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatchLookup[OpBatchType::Count]; + + // Maps batch ids to the most recent *non-merging* batch of that id + OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr }; + + std::vector<Rect> mClearRects; +}; + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index b6f50b111ab5..612cdfdc7185 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -87,7 +87,7 @@ class RenderNode; */ class RenderNode : public VirtualLightRefBase { friend class TestUtils; // allow TestUtils to access syncDisplayList / syncProperties -friend class OpReorderer; +friend class FrameReorderer; public: enum DirtyPropertyMask { GENERIC = 1 << 1, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 1af8f804e72a..fff8e0968ee6 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -31,7 +31,7 @@ #include "utils/TimeUtils.h" #if HWUI_NEW_OPS -#include "OpReorderer.h" +#include "FrameReorderer.h" #endif #include <cutils/properties.h> @@ -338,7 +338,7 @@ void CanvasContext::draw() { mEglManager.damageFrame(frame, dirty); #if HWUI_NEW_OPS - OpReorderer reorderer(mLayerUpdateQueue, dirty, frame.width(), frame.height(), + FrameReorderer reorderer(mLayerUpdateQueue, dirty, frame.width(), frame.height(), mRenderNodes, mLightCenter); mLayerUpdateQueue.clear(); BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(), diff --git a/libs/hwui/tests/microbench/OpReordererBench.cpp b/libs/hwui/tests/microbench/FrameReordererBench.cpp index 6bfe5a9a1028..b4c9a3626597 100644 --- a/libs/hwui/tests/microbench/OpReordererBench.cpp +++ b/libs/hwui/tests/microbench/FrameReordererBench.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 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. @@ -19,8 +19,8 @@ #include "BakedOpState.h" #include "BakedOpDispatcher.h" #include "BakedOpRenderer.h" +#include "FrameReorderer.h" #include "LayerUpdateQueue.h" -#include "OpReorderer.h" #include "RecordedOp.h" #include "RecordingCanvas.h" #include "tests/common/TestContext.h" @@ -61,20 +61,20 @@ static std::vector<sp<RenderNode>> createTestNodeList() { return vec; } -BENCHMARK_NO_ARG(BM_OpReorderer_defer); -void BM_OpReorderer_defer::Run(int iters) { +BENCHMARK_NO_ARG(BM_FrameBuilder_defer); +void BM_FrameBuilder_defer::Run(int iters) { auto nodes = createTestNodeList(); StartBenchmarkTiming(); for (int i = 0; i < iters; i++) { - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200, nodes, sLightCenter); MicroBench::DoNotOptimize(&reorderer); } StopBenchmarkTiming(); } -BENCHMARK_NO_ARG(BM_OpReorderer_deferAndRender); -void BM_OpReorderer_deferAndRender::Run(int iters) { +BENCHMARK_NO_ARG(BM_FrameBuilder_deferAndRender); +void BM_FrameBuilder_deferAndRender::Run(int iters) { TestUtils::runOnRenderThread([this, iters](RenderThread& thread) { auto nodes = createTestNodeList(); BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128 }; @@ -84,7 +84,7 @@ void BM_OpReorderer_deferAndRender::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; i++) { - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200, nodes, sLightCenter); BakedOpRenderer renderer(caches, renderState, true, lightInfo); @@ -117,7 +117,7 @@ static void benchDeferScene(testing::Benchmark& benchmark, int iters, const char auto nodes = getSyncedSceneNodes(sceneName); benchmark.StartBenchmarkTiming(); for (int i = 0; i < iters; i++) { - OpReorderer reorderer(sEmptyLayerUpdateQueue, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h, nodes, sLightCenter); MicroBench::DoNotOptimize(&reorderer); @@ -136,7 +136,7 @@ static void benchDeferAndRenderScene(testing::Benchmark& benchmark, benchmark.StartBenchmarkTiming(); for (int i = 0; i < iters; i++) { - OpReorderer reorderer(sEmptyLayerUpdateQueue, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h, nodes, sLightCenter); @@ -148,13 +148,13 @@ static void benchDeferAndRenderScene(testing::Benchmark& benchmark, }); } -BENCHMARK_NO_ARG(BM_OpReorderer_listview_defer); -void BM_OpReorderer_listview_defer::Run(int iters) { +BENCHMARK_NO_ARG(BM_FrameBuilder_listview_defer); +void BM_FrameBuilder_listview_defer::Run(int iters) { benchDeferScene(*this, iters, "listview"); } -BENCHMARK_NO_ARG(BM_OpReorderer_listview_deferAndRender); -void BM_OpReorderer_listview_deferAndRender::Run(int iters) { +BENCHMARK_NO_ARG(BM_FrameBuilder_listview_deferAndRender); +void BM_FrameBuilder_listview_deferAndRender::Run(int iters) { benchDeferAndRenderScene(*this, iters, "listview"); } diff --git a/libs/hwui/tests/unit/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp index 3fd822d71310..b3506869e0dc 100644 --- a/libs/hwui/tests/unit/BakedOpStateTests.cpp +++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp @@ -176,29 +176,26 @@ TEST(ResolvedRenderState, construct_expandForStroke) { } TEST(BakedOpState, tryConstruct) { - LinearAllocator allocator; - Matrix4 translate100x0; translate100x0.loadTranslate(100, 0, 0); SkPaint paint; ClipRect clip(Rect(100, 200)); - { - RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, &clip, &paint); - auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); - BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp); - - EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed - EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op - } - { - RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), &clip, &paint); - auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); - BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, successOp); - EXPECT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed - EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op - } + LinearAllocator allocator; + RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), &clip, &paint); + auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); + EXPECT_NE(nullptr, BakedOpState::tryConstruct(allocator, *snapshot, successOp)) + << "successOp NOT rejected by clip, so should be constructed"; + size_t successAllocSize = allocator.usedSize(); + EXPECT_LE(64u, successAllocSize) << "relatively large alloc for non-rejected op"; + + RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, &clip, &paint); + EXPECT_EQ(nullptr, BakedOpState::tryConstruct(allocator, *snapshot, rejectOp)) + << "rejectOp rejected by clip, so should not be constructed"; + + // NOTE: this relies on the clip having already been serialized by the op above + EXPECT_EQ(successAllocSize, allocator.usedSize()) << "no extra allocation used for rejected op"; } TEST(BakedOpState, tryShadowOpConstruct) { @@ -207,15 +204,16 @@ TEST(BakedOpState, tryShadowOpConstruct) { auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234); - EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed - EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op + EXPECT_EQ(nullptr, bakedState) << "op should be rejected by clip, so not constructed"; + EXPECT_EQ(0u, allocator.usedSize()) << "no serialization, even for clip," + "since op is quick rejected based on snapshot clip"; } { auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234); - ASSERT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed - EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op + ASSERT_NE(nullptr, bakedState) << "NOT rejected by clip, so op should be constructed"; + EXPECT_LE(64u, allocator.usedSize()) << "relatively large alloc for non-rejected op"; } } diff --git a/libs/hwui/tests/unit/OpReordererTests.cpp b/libs/hwui/tests/unit/FrameReordererTests.cpp index 701e4460c35f..9d2eb98a011d 100644 --- a/libs/hwui/tests/unit/OpReordererTests.cpp +++ b/libs/hwui/tests/unit/FrameReordererTests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 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. @@ -18,8 +18,8 @@ #include <BakedOpState.h> #include <DeferredLayerUpdater.h> +#include <FrameReorderer.h> #include <LayerUpdateQueue.h> -#include <OpReorderer.h> #include <RecordedOp.h> #include <RecordingCanvas.h> #include <tests/common/TestUtils.h> @@ -113,7 +113,7 @@ public: class FailRenderer : public TestRendererBase {}; -TEST(OpReorderer, simple) { +TEST(FrameReorderer, simple) { class SimpleTestRenderer : public TestRendererBase { public: void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { @@ -138,14 +138,14 @@ TEST(OpReorderer, simple) { canvas.drawRect(0, 0, 100, 200, SkPaint()); canvas.drawBitmap(bitmap, 10, 10, nullptr); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200, createSyncedNodeList(node), sLightCenter); SimpleTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end } -TEST(OpReorderer, simpleStroke) { +TEST(FrameReorderer, simpleStroke) { class SimpleStrokeTestRenderer : public TestRendererBase { public: void onPointsOp(const PointsOp& op, const BakedOpState& state) override { @@ -164,14 +164,14 @@ TEST(OpReorderer, simpleStroke) { strokedPaint.setStrokeWidth(10); canvas.drawPoint(50, 50, strokedPaint); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200, createSyncedNodeList(node), sLightCenter); SimpleStrokeTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(1, renderer.getIndex()); } -TEST(OpReorderer, simpleRejection) { +TEST(FrameReorderer, simpleRejection) { auto node = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); @@ -179,14 +179,14 @@ TEST(OpReorderer, simpleRejection) { canvas.drawRect(0, 0, 400, 400, SkPaint()); canvas.restore(); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(node), sLightCenter); FailRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); } -TEST(OpReorderer, simpleBatching) { +TEST(FrameReorderer, simpleBatching) { const int LOOPS = 5; class SimpleBatchingTestRenderer : public TestRendererBase { public: @@ -214,7 +214,7 @@ TEST(OpReorderer, simpleBatching) { canvas.restore(); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(node), sLightCenter); SimpleBatchingTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); @@ -222,7 +222,7 @@ TEST(OpReorderer, simpleBatching) { << "Expect number of ops = 2 * loop count"; } -TEST(OpReorderer, clippedMerging) { +TEST(FrameReorderer, clippedMerging) { class ClippedMergingTestRenderer : public TestRendererBase { public: void onMergedBitmapOps(const MergedBakedOpList& opList) override { @@ -255,14 +255,14 @@ TEST(OpReorderer, clippedMerging) { canvas.drawBitmap(bitmap, 40, 70, nullptr); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100, createSyncedNodeList(node), sLightCenter); ClippedMergingTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(4, renderer.getIndex()); } -TEST(OpReorderer, textMerging) { +TEST(FrameReorderer, textMerging) { class TextMergingTestRenderer : public TestRendererBase { public: void onMergedTextOps(const MergedBakedOpList& opList) override { @@ -283,14 +283,14 @@ TEST(OpReorderer, textMerging) { TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400, createSyncedNodeList(node), sLightCenter); TextMergingTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops"; } -TEST(OpReorderer, textStrikethrough) { +TEST(FrameReorderer, textStrikethrough) { const int LOOPS = 5; class TextStrikethroughTestRenderer : public TestRendererBase { public: @@ -314,7 +314,7 @@ TEST(OpReorderer, textStrikethrough) { TestUtils::drawTextToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1)); } }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000, createSyncedNodeList(node), sLightCenter); TextStrikethroughTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); @@ -322,7 +322,7 @@ TEST(OpReorderer, textStrikethrough) { << "Expect number of ops = 2 * loop count"; } -RENDERTHREAD_TEST(OpReorderer, textureLayer) { +RENDERTHREAD_TEST(FrameReorderer, textureLayer) { class TextureLayerTestRenderer : public TestRendererBase { public: void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override { @@ -348,14 +348,14 @@ RENDERTHREAD_TEST(OpReorderer, textureLayer) { canvas.drawLayer(layerUpdater.get()); canvas.restore(); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(node), sLightCenter); TextureLayerTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(1, renderer.getIndex()); } -TEST(OpReorderer, renderNode) { +TEST(FrameReorderer, renderNode) { class RenderNodeTestRenderer : public TestRendererBase { public: void onRectOp(const RectOp& op, const BakedOpState& state) override { @@ -393,13 +393,13 @@ TEST(OpReorderer, renderNode) { canvas.restore(); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(parent), sLightCenter); RenderNodeTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); } -TEST(OpReorderer, clipped) { +TEST(FrameReorderer, clipped) { class ClippedTestRenderer : public TestRendererBase { public: void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override { @@ -416,14 +416,14 @@ TEST(OpReorderer, clipped) { canvas.drawBitmap(bitmap, 0, 0, nullptr); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver 200, 200, createSyncedNodeList(node), sLightCenter); ClippedTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); } -TEST(OpReorderer, saveLayer_simple) { +TEST(FrameReorderer, saveLayer_simple) { class SaveLayerSimpleTestRenderer : public TestRendererBase { public: OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override { @@ -459,14 +459,14 @@ TEST(OpReorderer, saveLayer_simple) { canvas.drawRect(10, 10, 190, 190, SkPaint()); canvas.restore(); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(node), sLightCenter); SaveLayerSimpleTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(4, renderer.getIndex()); } -TEST(OpReorderer, saveLayer_nested) { +TEST(FrameReorderer, saveLayer_nested) { /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as: * - startTemporaryLayer2, rect2 endLayer2 * - startTemporaryLayer1, rect1, drawLayer2, endLayer1 @@ -531,14 +531,14 @@ TEST(OpReorderer, saveLayer_nested) { canvas.restore(); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800, createSyncedNodeList(node), sLightCenter); SaveLayerNestedTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(10, renderer.getIndex()); } -TEST(OpReorderer, saveLayer_contentRejection) { +TEST(FrameReorderer, saveLayer_contentRejection) { auto node = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); @@ -551,7 +551,7 @@ TEST(OpReorderer, saveLayer_contentRejection) { canvas.restore(); canvas.restore(); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(node), sLightCenter); FailRenderer renderer; @@ -559,7 +559,7 @@ TEST(OpReorderer, saveLayer_contentRejection) { reorderer.replayBakedOps<TestDispatcher>(renderer); } -TEST(OpReorderer, saveLayerUnclipped_simple) { +TEST(FrameReorderer, saveLayerUnclipped_simple) { class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase { public: void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override { @@ -594,14 +594,14 @@ TEST(OpReorderer, saveLayerUnclipped_simple) { canvas.drawRect(0, 0, 200, 200, SkPaint()); canvas.restore(); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(node), sLightCenter); SaveLayerUnclippedSimpleTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(4, renderer.getIndex()); } -TEST(OpReorderer, saveLayerUnclipped_mergedClears) { +TEST(FrameReorderer, saveLayerUnclipped_mergedClears) { class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase { public: void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override { @@ -648,7 +648,7 @@ TEST(OpReorderer, saveLayerUnclipped_mergedClears) { canvas.drawRect(0, 0, 100, 100, SkPaint()); canvas.restoreToCount(restoreTo); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(node), sLightCenter); SaveLayerUnclippedMergedClearsTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); @@ -660,7 +660,7 @@ TEST(OpReorderer, saveLayerUnclipped_mergedClears) { * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe */ -TEST(OpReorderer, saveLayerUnclipped_complex) { +TEST(FrameReorderer, saveLayerUnclipped_complex) { class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase { public: OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) { @@ -710,14 +710,14 @@ TEST(OpReorderer, saveLayerUnclipped_complex) { canvas.restore(); canvas.restore(); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600, createSyncedNodeList(node), sLightCenter); SaveLayerUnclippedComplexTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(12, renderer.getIndex()); } -RENDERTHREAD_TEST(OpReorderer, hwLayer_simple) { +RENDERTHREAD_TEST(FrameReorderer, hwLayer_simple) { class HwLayerSimpleTestRenderer : public TestRendererBase { public: void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override { @@ -768,7 +768,7 @@ RENDERTHREAD_TEST(OpReorderer, hwLayer_simple) { LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75)); - OpReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, syncedNodeList, sLightCenter); HwLayerSimpleTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); @@ -778,7 +778,7 @@ RENDERTHREAD_TEST(OpReorderer, hwLayer_simple) { *layerHandle = nullptr; } -RENDERTHREAD_TEST(OpReorderer, hwLayer_complex) { +RENDERTHREAD_TEST(FrameReorderer, hwLayer_complex) { /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as: * - startRepaintLayer(child), rect(grey), endLayer * - startTemporaryLayer, drawLayer(child), endLayer @@ -869,7 +869,7 @@ RENDERTHREAD_TEST(OpReorderer, hwLayer_complex) { layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100)); layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200)); - OpReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, syncedList, sLightCenter); HwLayerComplexTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); @@ -894,7 +894,7 @@ static void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z); canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership } -TEST(OpReorderer, zReorder) { +TEST(FrameReorderer, zReorder) { class ZReorderTestRenderer : public TestRendererBase { public: void onRectOp(const RectOp& op, const BakedOpState& state) override { @@ -918,14 +918,14 @@ TEST(OpReorderer, zReorder) { drawOrderedRect(&canvas, 8); drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100, createSyncedNodeList(parent), sLightCenter); ZReorderTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(10, renderer.getIndex()); }; -TEST(OpReorderer, projectionReorder) { +TEST(FrameReorderer, projectionReorder) { static const int scrollX = 5; static const int scrollY = 10; class ProjectionReorderTestRenderer : public TestRendererBase { @@ -1001,7 +1001,7 @@ TEST(OpReorderer, projectionReorder) { canvas.restore(); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100, createSyncedNodeList(parent), sLightCenter); ProjectionReorderTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); @@ -1020,7 +1020,7 @@ static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) { }); } -TEST(OpReorderer, shadow) { +TEST(FrameReorderer, shadow) { class ShadowTestRenderer : public TestRendererBase { public: void onShadowOp(const ShadowOp& op, const BakedOpState& state) override { @@ -1044,14 +1044,14 @@ TEST(OpReorderer, shadow) { canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get()); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(parent), sLightCenter); ShadowTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(2, renderer.getIndex()); } -TEST(OpReorderer, shadowSaveLayer) { +TEST(FrameReorderer, shadowSaveLayer) { class ShadowSaveLayerTestRenderer : public TestRendererBase { public: OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override { @@ -1085,14 +1085,14 @@ TEST(OpReorderer, shadowSaveLayer) { canvas.restoreToCount(count); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(parent), (Vector3) { 100, 100, 100 }); ShadowSaveLayerTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(5, renderer.getIndex()); } -RENDERTHREAD_TEST(OpReorderer, shadowHwLayer) { +RENDERTHREAD_TEST(FrameReorderer, shadowHwLayer) { class ShadowHwLayerTestRenderer : public TestRendererBase { public: void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override { @@ -1135,7 +1135,7 @@ RENDERTHREAD_TEST(OpReorderer, shadowHwLayer) { auto syncedList = createSyncedNodeList(parent); LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100)); - OpReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, syncedList, (Vector3) { 100, 100, 100 }); ShadowHwLayerTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); @@ -1145,7 +1145,7 @@ RENDERTHREAD_TEST(OpReorderer, shadowHwLayer) { *layerHandle = nullptr; } -TEST(OpReorderer, shadowLayering) { +TEST(FrameReorderer, shadowLayering) { class ShadowLayeringTestRenderer : public TestRendererBase { public: void onShadowOp(const ShadowOp& op, const BakedOpState& state) override { @@ -1164,7 +1164,7 @@ TEST(OpReorderer, shadowLayering) { canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get()); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(parent), sLightCenter); ShadowLayeringTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); @@ -1192,14 +1192,14 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac canvas.drawRect(0, 0, 100, 100, paint); }); - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200, + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200, createSyncedNodeList(node), sLightCenter); PropertyTestRenderer renderer(opValidateCallback); reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op"; } -TEST(OpReorderer, renderPropOverlappingRenderingAlpha) { +TEST(FrameReorderer, renderPropOverlappingRenderingAlpha) { testProperty([](RenderProperties& properties) { properties.setAlpha(0.5f); properties.setHasOverlappingRendering(false); @@ -1208,7 +1208,7 @@ TEST(OpReorderer, renderPropOverlappingRenderingAlpha) { }); } -TEST(OpReorderer, renderPropClipping) { +TEST(FrameReorderer, renderPropClipping) { testProperty([](RenderProperties& properties) { properties.setClipToBounds(true); properties.setClipBounds(Rect(10, 20, 300, 400)); @@ -1218,7 +1218,7 @@ TEST(OpReorderer, renderPropClipping) { }); } -TEST(OpReorderer, renderPropRevealClip) { +TEST(FrameReorderer, renderPropRevealClip) { testProperty([](RenderProperties& properties) { properties.mutableRevealClip().set(true, 50, 50, 25); }, [](const RectOp& op, const BakedOpState& state) { @@ -1229,7 +1229,7 @@ TEST(OpReorderer, renderPropRevealClip) { }); } -TEST(OpReorderer, renderPropOutlineClip) { +TEST(FrameReorderer, renderPropOutlineClip) { testProperty([](RenderProperties& properties) { properties.mutableOutline().setShouldClip(true); properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f); @@ -1241,7 +1241,7 @@ TEST(OpReorderer, renderPropOutlineClip) { }); } -TEST(OpReorderer, renderPropTransform) { +TEST(FrameReorderer, renderPropTransform) { testProperty([](RenderProperties& properties) { properties.setLeftTopRightBottom(10, 10, 110, 110); @@ -1334,7 +1334,7 @@ void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData, }); auto nodes = createSyncedNodeList(node); // sync before querying height - OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter); + FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter); SaveLayerAlphaClipTestRenderer renderer(outObservedData); reorderer.replayBakedOps<TestDispatcher>(renderer); @@ -1342,7 +1342,7 @@ void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData, ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior."; } -TEST(OpReorderer, renderPropSaveLayerAlphaClipBig) { +TEST(FrameReorderer, renderPropSaveLayerAlphaClipBig) { SaveLayerAlphaData observedData; testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) { properties.setTranslationX(10); // offset rendering content @@ -1358,7 +1358,7 @@ TEST(OpReorderer, renderPropSaveLayerAlphaClipBig) { << "expect content to be translated as part of being clipped"; } -TEST(OpReorderer, renderPropSaveLayerAlphaRotate) { +TEST(FrameReorderer, renderPropSaveLayerAlphaRotate) { SaveLayerAlphaData observedData; testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) { // Translate and rotate the view so that the only visible part is the top left corner of @@ -1377,7 +1377,7 @@ TEST(OpReorderer, renderPropSaveLayerAlphaRotate) { EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix); } -TEST(OpReorderer, renderPropSaveLayerAlphaScale) { +TEST(FrameReorderer, renderPropSaveLayerAlphaScale) { SaveLayerAlphaData observedData; testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) { properties.setPivotX(0); diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 359a7a97aa81..9c01f4f4d7a2 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -161,7 +161,7 @@ import android.view.SurfaceView; * </pre> * */ -public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback { +public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2 { private final static String TAG = "GLSurfaceView"; private final static boolean LOG_ATTACH_DETACH = false; private final static boolean LOG_THREADS = false; @@ -542,6 +542,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } /** + * This method is part of the SurfaceHolder.Callback interface, and is + * not normally called or subclassed by clients of GLSurfaceView. + */ + @Override + public void surfaceRedrawNeeded(SurfaceHolder holder) { + mGLThread.requestRenderAndWait(); + } + + + /** * Inform the view that the activity is paused. The owner of this view must * call this method when the activity is paused. Calling this method will * pause the rendering thread. @@ -1226,6 +1236,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mHeight = 0; mRequestRender = true; mRenderMode = RENDERMODE_CONTINUOUSLY; + mWantRenderNotification = false; mGLSurfaceViewWeakRef = glSurfaceViewWeakRef; } @@ -1271,6 +1282,8 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mEglHelper = new EglHelper(mGLSurfaceViewWeakRef); mHaveEglContext = false; mHaveEglSurface = false; + mWantRenderNotification = false; + try { GL10 gl = null; boolean createEglContext = false; @@ -1278,7 +1291,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback boolean createGlInterface = false; boolean lostEglContext = false; boolean sizeChanged = false; - boolean wantRenderNotification = false; boolean doRenderNotification = false; boolean askedToReleaseEglContext = false; int w = 0; @@ -1383,7 +1395,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (LOG_SURFACE) { Log.i("GLThread", "sending render notification tid=" + getId()); } - wantRenderNotification = false; + mWantRenderNotification = false; doRenderNotification = false; mRenderComplete = true; sGLThreadManager.notifyAll(); @@ -1422,7 +1434,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback sizeChanged = true; w = mWidth; h = mHeight; - wantRenderNotification = true; + mWantRenderNotification = true; if (LOG_SURFACE) { Log.i("GLThread", "noticing that we want render notification tid=" @@ -1562,7 +1574,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback break; } - if (wantRenderNotification) { + if (mWantRenderNotification) { doRenderNotification = true; } } @@ -1611,6 +1623,23 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } } + public void requestRenderAndWait() { + synchronized(sGLThreadManager) { + mWantRenderNotification = true; + mRequestRender = true; + mRenderComplete = false; + sGLThreadManager.notifyAll(); + while (!mExited && !mPaused && mRenderComplete == false) { + try { + sGLThreadManager.wait(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + + } + } + public void surfaceCreated() { synchronized(sGLThreadManager) { if (LOG_THREADS) { @@ -1766,6 +1795,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback private int mHeight; private int mRenderMode; private boolean mRequestRender; + private boolean mWantRenderNotification; private boolean mRenderComplete; private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>(); private boolean mSizeChanged = true; diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml index 7e0649be722d..a3cfde825f47 100644 --- a/packages/DocumentsUI/res/menu/activity.xml +++ b/packages/DocumentsUI/res/menu/activity.xml @@ -15,11 +15,19 @@ --> <menu xmlns:android="http://schemas.android.com/apk/res/android"> +<!-- showAsAction flag impacts the behavior of SearchView. + When set to collapseActionView, collapsing SearchView to icon is the + default behavior. It would fit UX, however after expanding SearchView is + shown on the left site of the toolbar (replacing title). Since no way to + prevent this behavior was found, the flag is set to always. SearchView is + always visible by default and it is being collapse manually by calling + setIconified() method +--> <item android:id="@+id/menu_search" android:title="@string/menu_search" android:icon="@drawable/ic_menu_search" - android:showAsAction="always|collapseActionView" + android:showAsAction="always" android:actionViewClass="android.widget.SearchView" android:imeOptions="actionSearch" /> <item diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml index 153c673caf56..c868d340e901 100644 --- a/packages/DocumentsUI/res/values/colors.xml +++ b/packages/DocumentsUI/res/values/colors.xml @@ -33,4 +33,6 @@ <color name="item_doc_background">#fffafafa</color> <color name="item_doc_background_selected">#ffe0f2f1</color> + <color name="menu_search_background">#ff676f74</color> + </resources> diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java index 7f710fc58181..180a48eaca99 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -38,12 +38,14 @@ import android.provider.DocumentsContract; import android.provider.DocumentsContract.Root; import android.support.annotation.LayoutRes; import android.support.annotation.Nullable; +import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; -import android.view.MenuItem.OnActionExpandListener; import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnFocusChangeListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; @@ -218,6 +220,7 @@ public abstract class BaseActivity extends Activity { case R.id.menu_advanced: case R.id.menu_file_size: case R.id.menu_new_window: + case R.id.menu_search: break; default: item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); @@ -318,6 +321,8 @@ public abstract class BaseActivity extends Activity { * the (abstract) directoryChanged method will be called. * @param anim */ + // TODO: Refactor the usage of the method - now it is called not only when the directory + // changed, but also to refresh the content of the directory while searching final void onCurrentDirectoryChanged(int anim) { mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN); onDirectoryChanged(anim); @@ -328,7 +333,11 @@ public abstract class BaseActivity extends Activity { } updateActionBar(); - invalidateOptionsMenu(); + + // Prevents searchView from being recreated while searching + if (!mSearchManager.isSearching()) { + invalidateOptionsMenu(); + } } final List<String> getExcludedAuthorities() { @@ -720,7 +729,7 @@ public abstract class BaseActivity extends Activity { * Facade over the various search parts in the menu. */ final class SearchManager implements - SearchView.OnCloseListener, OnActionExpandListener, OnQueryTextListener, + SearchView.OnCloseListener, OnQueryTextListener, OnClickListener, OnFocusChangeListener, DocumentsToolBar.OnActionViewCollapsedListener { private boolean mSearchExpanded; @@ -738,9 +747,10 @@ public abstract class BaseActivity extends Activity { mView = (SearchView) mMenu.getActionView(); mActionBar.setOnActionViewCollapsedListener(this); - mMenu.setOnActionExpandListener(this); mView.setOnQueryTextListener(this); mView.setOnCloseListener(this); + mView.setOnSearchClickListener(this); + mView.setOnQueryTextFocusChangeListener(this); } /** @@ -793,19 +803,13 @@ public abstract class BaseActivity extends Activity { * search currently. */ boolean cancelSearch() { - boolean collapsed = false; - boolean closed = false; - - if (mActionBar.hasExpandedActionView()) { - mActionBar.collapseActionView(); - collapsed = true; - } - if (isExpanded() || isSearching()) { - onClose(); - closed = true; + // If the query string is not empty search view won't get iconified + mView.setQuery("", false); + mView.setIconified(true); + return true; } - return collapsed || closed; + return false; } boolean isSearching() { @@ -816,6 +820,11 @@ public abstract class BaseActivity extends Activity { return mSearchExpanded; } + /** + * Clears the search. + * @return True if the default behavior of clearing/dismissing SearchView should be + * overridden. False otherwise. + */ @Override public boolean onClose() { mSearchExpanded = false; @@ -824,33 +833,33 @@ public abstract class BaseActivity extends Activity { return false; } - mState.currentSearch = null; - onCurrentDirectoryChanged(ANIM_NONE); + mView.setBackgroundColor( + getResources().getColor(android.R.color.transparent, null)); + + // Refresh the directory if a search was done + if(mState.currentSearch != null) { + mState.currentSearch = null; + onCurrentDirectoryChanged(ANIM_NONE); + } + return false; } + /** + * Sets mSearchExpanded. + * Called when search icon is clicked to start search. + * Used to detect when the view expanded instead of onMenuItemActionExpand, because + * SearchView has showAsAction set to always and onMenuItemAction* methods are not called. + */ @Override - public boolean onMenuItemActionExpand(MenuItem item) { + public void onClick (View v) { mSearchExpanded = true; - updateActionBar(); - return true; - } - - @Override - public boolean onMenuItemActionCollapse(MenuItem item) { - mSearchExpanded = false; - if (mIgnoreNextCollapse) { - mIgnoreNextCollapse = false; - return true; - } - mState.currentSearch = null; - onCurrentDirectoryChanged(ANIM_NONE); - return true; + mView.setBackgroundColor( + getResources().getColor(R.color.menu_search_background, null)); } @Override public boolean onQueryTextSubmit(String query) { - mSearchExpanded = true; mState.currentSearch = query; mView.clearFocus(); onCurrentDirectoryChanged(ANIM_NONE); @@ -863,6 +872,18 @@ public abstract class BaseActivity extends Activity { } @Override + public void onFocusChange(View v, boolean hasFocus) { + if(!hasFocus) { + if(mState.currentSearch == null) { + mView.setIconified(true); + } + else if(TextUtils.isEmpty(mView.getQuery())) { + cancelSearch(); + } + } + } + + @Override public void onActionViewCollapsed() { updateActionBar(); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index ca8ef2e65bcb..223af896ae23 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -308,8 +308,10 @@ public class DocumentsActivity extends BaseActivity { mSearchManager.showMenu(!picking); // No display options in recent directories - grid.setVisible(!(picking && recents)); - list.setVisible(!(picking && recents)); + if (picking && recents) { + grid.setVisible(false); + list.setVisible(false); + } fileSize.setVisible(fileSize.isVisible() && !picking); settings.setVisible(false); diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java index 4c844c422ff5..beff196509b2 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java @@ -297,7 +297,7 @@ public class RootsFragment extends Fragment { for (final RootInfo root : roots) { final RootItem item = new RootItem(root); - if (root.isLibrary() || root.isHome()) { + if (root.isLibrary()) { libraries.add(item); } else { others.add(item); diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java index 84ab85e35dc0..898713f75e62 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -407,7 +407,6 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi state.derivedMode = result.mode; } state.derivedSortOrder = result.sortOrder; - ((BaseActivity) context).onStateChanged(); updateDisplayState(); diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml index 0f34e9ec92f0..6179b4ba7457 100644 --- a/packages/PrintSpooler/res/values-af/strings.xml +++ b/packages/PrintSpooler/res/values-af/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kanselleer tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Drukkerfout by <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Drukker het <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> geblokkeer"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>-druktake</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>-druktaak</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Kanselleer"</string> <string name="restart" msgid="2472034227037808749">"Herbegin"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met drukker nie"</string> diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml index a6e1abfd753b..2f94e1efb5eb 100644 --- a/packages/PrintSpooler/res/values-am/strings.xml +++ b/packages/PrintSpooler/res/values-am/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በመተው ላይ"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"የአታሚ ስህተት <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"አታሚ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን አግዷል"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> የህትመት ስራ</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> የህትመት ስራ</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"ይቅር"</string> <string name="restart" msgid="2472034227037808749">"እንደገና ጀምር"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"ከአታሚ ጋር ምንም ግንኙነት የለም"</string> diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml index 0291b7d9670c..29767c34f7a4 100644 --- a/packages/PrintSpooler/res/values-ar/strings.xml +++ b/packages/PrintSpooler/res/values-ar/strings.xml @@ -73,14 +73,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"جارٍ إلغاء <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"خطا في الطابعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"رفضت الطابعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="zero"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> مهمة طباعة</item> - <item quantity="two">مهمتا طباعة (<xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>)</item> - <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> مهام طباعة</item> - <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> مهمة طباعة</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> من مهام الطباعة</item> - <item quantity="one">مهمة طباعة واحدة (<xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>)</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"إلغاء"</string> <string name="restart" msgid="2472034227037808749">"إعادة تشغيل"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"لا يوجد اتصال بالطابعة"</string> diff --git a/packages/PrintSpooler/res/values-az-rAZ/strings.xml b/packages/PrintSpooler/res/values-az-rAZ/strings.xml index e1627936ecdb..3316b30e02e8 100644 --- a/packages/PrintSpooler/res/values-az-rAZ/strings.xml +++ b/packages/PrintSpooler/res/values-az-rAZ/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ləğv edilir"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer xətası <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> işini blokladı"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> çap işi</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> çap işi</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Ləğv et"</string> <string name="restart" msgid="2472034227037808749">"Yenidən başlat"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Printerə heç bir bağlantı yoxdur"</string> diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml index d6e439cdf642..86baf10114e1 100644 --- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml +++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml @@ -70,11 +70,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazuje se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Greška štampača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Štampač je blokirao <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one">Zadaci štampanja <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="few">Zadaci štampanja <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="other">Zadaci štampanja <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Otkaži"</string> <string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Nema veze sa štampačem"</string> diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml index c23935437aae..2c02b74cb48e 100644 --- a/packages/PrintSpooler/res/values-bg/strings.xml +++ b/packages/PrintSpooler/res/values-bg/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се анулира"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка в принтера при „<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтерът блокира при „<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other">Задания за отпечатване: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="one">Задание за отпечатване: <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Отказ"</string> <string name="restart" msgid="2472034227037808749">"Рестартиране"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Няма връзка с принтера"</string> diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml index 17a1a3541796..d48d91d8c7ae 100644 --- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml +++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> বাতিল করা হচ্ছে"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> মুদ্রক ত্রুটি"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"মুদ্রক <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> অবরুদ্ধ করেছে"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> মুদ্রণ কার্যগুলি</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> মুদ্রণ কার্যগুলি</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"বাতিল করুন"</string> <string name="restart" msgid="2472034227037808749">"পুনর্সূচনা"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"মুদ্রকে কোনো সংযোগ নেই"</string> diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml index 25512067ce87..d0fd75ede8aa 100644 --- a/packages/PrintSpooler/res/values-ca/strings.xml +++ b/packages/PrintSpooler/res/values-ca/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"S\'està cancel·lant <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Error d\'impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Impressora bloquejada <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tasques d\'impressió</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tasca d\'impressió</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Cancel·la"</string> <string name="restart" msgid="2472034227037808749">"Reinicia"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"No hi ha connexió amb la impressora"</string> diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml index 0bb48f8e199e..bec34aca53be 100644 --- a/packages/PrintSpooler/res/values-cs/strings.xml +++ b/packages/PrintSpooler/res/values-cs/strings.xml @@ -71,12 +71,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Rušení úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tiskárny u úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tiskárna blokuje úlohu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="few">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="many">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="other">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="one">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Zrušit"</string> <string name="restart" msgid="2472034227037808749">"Restartovat"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Nelze se připojit k tiskárně"</string> diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml index a9d042b5c51a..de2914614fc1 100644 --- a/packages/PrintSpooler/res/values-da/strings.xml +++ b/packages/PrintSpooler/res/values-da/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annulleres"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Udskriften <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> mislykkedes"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printeren har blokeret <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>-udskriftsjob</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>-udskriftsjob</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Annuller"</string> <string name="restart" msgid="2472034227037808749">"Genstart"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse til printer"</string> diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml index 4eb5d6a94d5a..054454ed3b00 100644 --- a/packages/PrintSpooler/res/values-de/strings.xml +++ b/packages/PrintSpooler/res/values-de/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird abgebrochen..."</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Druckerfehler <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Drucker hat <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> blockiert."</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other">Druckaufträge \"<xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>\"</item> - <item quantity="one">Druckauftrag \"<xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>\"</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Abbrechen"</string> <string name="restart" msgid="2472034227037808749">"Neu starten"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Keine Verbindung zum Drucker"</string> diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml index cd35785b528c..abae9614ff1d 100644 --- a/packages/PrintSpooler/res/values-el/strings.xml +++ b/packages/PrintSpooler/res/values-el/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ακύρωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Σφάλμα εκτυπωτή <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Ο εκτυπωτής απέκλεισε <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> εργασίες εκτύπωσης</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> εργασία εκτύπωσης</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Ακύρωση"</string> <string name="restart" msgid="2472034227037808749">"Επανεκκίνηση"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Δεν υπάρχει σύνδεση με εκτυπωτή"</string> diff --git a/packages/PrintSpooler/res/values-en-rAU/strings.xml b/packages/PrintSpooler/res/values-en-rAU/strings.xml index 753d9dfc5bd8..b656dcdbea63 100644 --- a/packages/PrintSpooler/res/values-en-rAU/strings.xml +++ b/packages/PrintSpooler/res/values-en-rAU/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blocked <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> print jobs</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> print job</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Cancel"</string> <string name="restart" msgid="2472034227037808749">"Restart"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string> diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml index 753d9dfc5bd8..b656dcdbea63 100644 --- a/packages/PrintSpooler/res/values-en-rGB/strings.xml +++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blocked <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> print jobs</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> print job</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Cancel"</string> <string name="restart" msgid="2472034227037808749">"Restart"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string> diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml index 753d9dfc5bd8..b656dcdbea63 100644 --- a/packages/PrintSpooler/res/values-en-rIN/strings.xml +++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blocked <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> print jobs</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> print job</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Cancel"</string> <string name="restart" msgid="2472034227037808749">"Restart"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string> diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml index 1a0d5d85cec8..712bb8099a00 100644 --- a/packages/PrintSpooler/res/values-es-rUS/strings.xml +++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"La impresora bloqueó <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>."</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other">Trabajos de impresión: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="one">Trabajo de impresión: <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Cancelar"</string> <string name="restart" msgid="2472034227037808749">"Reiniciar"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora."</string> diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml index eac568d4bdfd..dfd6a6259070 100644 --- a/packages/PrintSpooler/res/values-es/strings.xml +++ b/packages/PrintSpooler/res/values-es/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"La impresora ha bloqueado <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other">Trabajos de impresión <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="one">Trabajo de impresión <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Cancelar"</string> <string name="restart" msgid="2472034227037808749">"Volver a empezar"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora"</string> diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml index 2cde25886420..7b962afe81f7 100644 --- a/packages/PrintSpooler/res/values-et-rEE/strings.xml +++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> tühistamine"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri viga: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blokeeris töö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> prinditööd</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> prinditöö</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Tühista"</string> <string name="restart" msgid="2472034227037808749">"Taaskäivita"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Printeriühendus puudub"</string> diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml index 96a3273f47ad..4551cc293e06 100644 --- a/packages/PrintSpooler/res/values-eu-rES/strings.xml +++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bertan behera uzten"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Errorea <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzean"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Inprimag. <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> blokeatu du"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> inprimatze-lanak</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> inprimatze-lana</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Utzi"</string> <string name="restart" msgid="2472034227037808749">"Berrabiarazi"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Inprimagailua ez dago konektatuta"</string> diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml index fdc39892836f..d85978d8c403 100644 --- a/packages/PrintSpooler/res/values-fa/strings.xml +++ b/packages/PrintSpooler/res/values-fa/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"در حال لغو <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"خطای چاپگر <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"چاپگر، کار <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> را مسدود کرد"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one">کار چاپ <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="other">کار چاپ <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"لغو"</string> <string name="restart" msgid="2472034227037808749">"راهاندازی مجدد"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"اتصال با چاپگر برقرار نیست"</string> diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml index 926739398cc7..44724597d184 100644 --- a/packages/PrintSpooler/res/values-fi/strings.xml +++ b/packages/PrintSpooler/res/values-fi/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Peruutetaan työ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Tulostinvirhe työlle <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tulostin esti työn <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tulostustyötä</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tulostustyö</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Peruuta"</string> <string name="restart" msgid="2472034227037808749">"Käynnistä uudelleen"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Ei yhteyttä tulostimeen"</string> diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml index bfb4862f249d..1d4531536639 100644 --- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml +++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »…"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression : « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Impression de « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> » bloquée"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâche d\'impression</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâches d\'impression</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Annuler"</string> <string name="restart" msgid="2472034227037808749">"Recommencer"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante"</string> diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml index de55e29a2140..df7dfef0f691 100644 --- a/packages/PrintSpooler/res/values-fr/strings.xml +++ b/packages/PrintSpooler/res/values-fr/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression pour \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Impression de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" bloquée"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâche d\'impression</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâches d\'impression</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Annuler"</string> <string name="restart" msgid="2472034227037808749">"Redémarrer"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante."</string> diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml index dc66084e7894..eae645008870 100644 --- a/packages/PrintSpooler/res/values-gl-rES/strings.xml +++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impresora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> traballos de impresión</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> traballo de impresión</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Cancelar"</string> <string name="restart" msgid="2472034227037808749">"Reiniciar"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Non hai conexión coa impresora"</string> diff --git a/packages/PrintSpooler/res/values-gu-rIN/strings.xml b/packages/PrintSpooler/res/values-gu-rIN/strings.xml index d05a3929ffbb..8028274ecdf9 100644 --- a/packages/PrintSpooler/res/values-gu-rIN/strings.xml +++ b/packages/PrintSpooler/res/values-gu-rIN/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ને રદ કરી રહ્યું છે"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"પ્રિન્ટર ભૂલ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"પ્રિન્ટરે <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> અવરોધિત કર્યું"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> છાપ જોબ</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> છાપ જોબ</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"રદ કરો"</string> <string name="restart" msgid="2472034227037808749">"પુનઃપ્રારંભ કરો"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"પ્રિન્ટર માટે કોઈ કનેક્શન નથી"</string> diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml index 8051900aaeee..5bfcc6e02c3c 100644 --- a/packages/PrintSpooler/res/values-hi/strings.xml +++ b/packages/PrintSpooler/res/values-hi/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द हो रहा है"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटर अवरोधित <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> प्रिंट कार्य</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> प्रिंट कार्य</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"अभी नहीं"</string> <string name="restart" msgid="2472034227037808749">"पुन: आरंभ करें"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटर के लिए कोई कनेक्शन नहीं"</string> diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml index 4dab4cc90e1e..bf244c5944ba 100644 --- a/packages/PrintSpooler/res/values-hr/strings.xml +++ b/packages/PrintSpooler/res/values-hr/strings.xml @@ -70,11 +70,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje zadatka <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Pogreška pisača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Pisač je blokirao <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadatak ispisa</item> - <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadatka ispisa</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadataka ispisa</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Odustani"</string> <string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Nema veze s pisačem"</string> diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml index 1a56ee73f707..6c608f1f0ff2 100644 --- a/packages/PrintSpooler/res/values-hu/strings.xml +++ b/packages/PrintSpooler/res/values-hu/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> törlése"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Nyomtatási hiba: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> letiltva."</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> nyomtatási feladat</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> nyomtatási feladat</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Mégse"</string> <string name="restart" msgid="2472034227037808749">"Újraindítás"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Nincs kapcsolat a nyomtatóval"</string> diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml index 7b99dcfac642..801410b5b575 100644 --- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml +++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ը չեղարկվում է"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Տպիչի սխալ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Տպիչն արգելափակել է <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ը"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> տպման աշխատանք</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> տպման աշխատանք</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Չեղարկել"</string> <string name="restart" msgid="2472034227037808749">"Վերագործարկել"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Տպիչի հետ կապ չկա"</string> diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml index a9912722ecb0..227a372bd577 100644 --- a/packages/PrintSpooler/res/values-in/strings.xml +++ b/packages/PrintSpooler/res/values-in/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Ada kesalahan printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer memblokir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other">Tugas cetak <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="one">Tugas cetak <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Batal"</string> <string name="restart" msgid="2472034227037808749">"Mulai Ulang"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Tidak ada sambungan ke printer"</string> diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml index e93f7023f5ea..f078ff84c4c7 100644 --- a/packages/PrintSpooler/res/values-is-rIS/strings.xml +++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hættir við <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Prentaravilla <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Prentari útilokaði <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> prentverk</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> prentverk</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Hætta við"</string> <string name="restart" msgid="2472034227037808749">"Endurræsa"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Engin tenging við prentara"</string> diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml index ffba3533a7fa..10b3601b33fd 100644 --- a/packages/PrintSpooler/res/values-it/strings.xml +++ b/packages/PrintSpooler/res/values-it/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annullamento di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Errore della stampante: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"La stampante ha bloccato <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> processi di stampa</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> processo di stampa</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Annulla"</string> <string name="restart" msgid="2472034227037808749">"Riavvia"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Nessun collegamento alla stampante"</string> diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml index 2ac109303cc0..8a04c7683139 100644 --- a/packages/PrintSpooler/res/values-iw/strings.xml +++ b/packages/PrintSpooler/res/values-iw/strings.xml @@ -71,12 +71,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"מבטל את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"שגיאת מדפסת ב-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"המדפסת חסמה את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="two"> עבודות הדפסה <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="many"> עבודות הדפסה <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="other"> עבודות הדפסה <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="one"> עבודת הדפסה <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"בטל"</string> <string name="restart" msgid="2472034227037808749">"הפעל מחדש"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"אין חיבור למדפסת"</string> diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml index 2c3c24de413d..a132fb1d85ed 100644 --- a/packages/PrintSpooler/res/values-ja/strings.xml +++ b/packages/PrintSpooler/res/values-ja/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>をキャンセルしています"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"プリンタエラー: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>をブロックしました"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>の印刷ジョブ</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>の印刷ジョブ</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"キャンセル"</string> <string name="restart" msgid="2472034227037808749">"再試行"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"プリンタに接続されていません"</string> diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml index 2b0285dc0c06..675245b6acea 100644 --- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml +++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"მიმდინარეობს <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ის გაუქმება"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"ბეჭდვის შეცდომა <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"პრინტერმა დაბლოკა <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ბეჭდვის დავალება</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ბეჭდვის დავალება</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"გაუქმება"</string> <string name="restart" msgid="2472034227037808749">"გადატვირთვა"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"პრინტერთან კავშირი არ არის"</string> diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml index fc099c9772d0..4c7c4f4a1787 100644 --- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml +++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> жұмысын тоқтатуда"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> принтер қателігі"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтер <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> жұмысын бөгеді"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> баспа тапсырмасы</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> баспа тапсырмасы</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Тоқтату"</string> <string name="restart" msgid="2472034227037808749">"Қайта бастау"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Принтермен байланыс жоқ"</string> diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml index b51091e803a8..fac7c0c9ad5b 100644 --- a/packages/PrintSpooler/res/values-km-rKH/strings.xml +++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"ការបោះបង់ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"កំហុសម៉ាស៊ីនបោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"ម៉ាស៊ីនបោះពុម្ពបានទប់ស្កាត់ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other">ការងារបោះពុម្ព <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="one">ការងារបោះពុម្ព <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"បោះបង់"</string> <string name="restart" msgid="2472034227037808749">"ចាប់ផ្ដើមឡើងវិញ"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មានការភ្ជាប់ទៅម៉ាស៊ីនបោះពុម្ព"</string> diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml index 5d5dee86654c..61279fc46fc7 100644 --- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml +++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ರದ್ದು ಮಾಡಲಾಗುತ್ತಿದೆ"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"ಮುದ್ರಕ ದೋಷ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"ಮುದ್ರಕವು <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ನಿರ್ಬಂಧಿಸಿದೆ"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ಮುದ್ರಣ ಕಾರ್ಯಗಳು</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ಮುದ್ರಣ ಕಾರ್ಯಗಳು</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"ರದ್ದುಮಾಡು"</string> <string name="restart" msgid="2472034227037808749">"ಮರುಪ್ರಾರಂಭಿಸು"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"ಮುದ್ರಕಕ್ಕೆ ಸಂಪರ್ಕವಿಲ್ಲ"</string> diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml index 98617e7841ee..fe47e55aff0d 100644 --- a/packages/PrintSpooler/res/values-ko/strings.xml +++ b/packages/PrintSpooler/res/values-ko/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 취소 중"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"프린터 오류: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"차단된 프린터: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> 인쇄 작업</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> 인쇄 작업</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"취소"</string> <string name="restart" msgid="2472034227037808749">"다시 시작"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"프린터와 연결되지 않음"</string> diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml index 2a11ff86508b..79b38d1658f0 100644 --- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml +++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> токтотулууда"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерде ката кетти: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтер бөгөттөдү: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> басуу тапшырмасы</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> басуу тапшырмасы</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Айнуу"</string> <string name="restart" msgid="2472034227037808749">"Кайра баштоо"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Принтер менен байланыш жок"</string> diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml index 788e5aaaf036..3140a258c05f 100644 --- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml +++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"ກຳລັງຍົກເລີກ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"ເຄື່ອງພິມເກີດຂໍ້ຜິດພາດ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"ເຄື່ອງພິມຖືກບລອກ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ງານພິມ</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ງານພິມ</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"ຍົກເລີກ"</string> <string name="restart" msgid="2472034227037808749">"ປິດເປີດໃໝ່"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"ບໍ່ມີການເຊື່ອມຕໍ່ຫາເຄື່ອງພິມ"</string> diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml index 1826e8ee283e..4f0772ed8fd5 100644 --- a/packages/PrintSpooler/res/values-lt/strings.xml +++ b/packages/PrintSpooler/res/values-lt/strings.xml @@ -71,12 +71,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Atšaukiama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Spausdintuvo klaida: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Spausdintuvas užblokavo: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduotis</item> - <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduotys</item> - <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduoties</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduočių</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Atšaukti"</string> <string name="restart" msgid="2472034227037808749">"Paleisti iš naujo"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Nėra ryšio su spausdintuvu"</string> diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml index 5c17efe402ff..0efa50fdf646 100644 --- a/packages/PrintSpooler/res/values-lv/strings.xml +++ b/packages/PrintSpooler/res/values-lv/strings.xml @@ -70,11 +70,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Pārtrauc drukas darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Printera kļūda ar darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printeris bloķēja darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="zero"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> drukas darbi</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> drukas darbs</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> drukas darbi</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Atcelt"</string> <string name="restart" msgid="2472034227037808749">"Restartēt"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Nav savienojuma ar printeri"</string> diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml index ebc1181f0d46..2805dee55689 100644 --- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml +++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се откажува"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка при печатење <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Печатачот го блокираше <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> работа за печатење</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> работи за печатење</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Откажи"</string> <string name="restart" msgid="2472034227037808749">"Рестартирај"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Нема поврзување со печатач"</string> diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml index c08a3d417744..9617a7a3f65a 100644 --- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml +++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> റദ്ദാക്കുന്നു"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"പ്രിന്റർ പിശക് <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"പ്രിന്റർ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> തടഞ്ഞു"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> പ്രിന്റ് ജോലികൾ</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> പ്രിന്റ് ജോലി</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"റദ്ദാക്കുക"</string> <string name="restart" msgid="2472034227037808749">"പുനരാരംഭിക്കുക"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"പ്രിന്ററിൽ കണക്ഷനൊന്നുമില്ല"</string> diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml index dcef28f0a4e8..59bb9bf2e136 100644 --- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml +++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Цуцлаж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерийн алдаа <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтер хориглогдсон <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ажлыг хэвлэх</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ажлыг хэвлэх</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Цуцлах"</string> <string name="restart" msgid="2472034227037808749">"Дахин эхлүүлэх"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Принтер холбогдоогүй байна"</string> diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml index 384f0ded5386..2b6661e0f491 100644 --- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml +++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करीत आहे"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटी <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटरने <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> अवरोधित केले"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> मुद्रण कार्य</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> मुद्रण कार्ये</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"रद्द करा"</string> <string name="restart" msgid="2472034227037808749">"रीस्टार्ट करा"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटरवर कोणतेही कनेक्शन नाही"</string> diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml index 19a6e765751d..c0666273dd0b 100644 --- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml +++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Ralat pencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Pencetak disekat <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other">Kerja cetakan <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="one">Kerja cetakan <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Batal"</string> <string name="restart" msgid="2472034227037808749">"Mulakan semula"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Tiada sambungan ke pencetak"</string> diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml index d3c0672b88e0..a63e85e15805 100644 --- a/packages/PrintSpooler/res/values-my-rMM/strings.xml +++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို ပယ်ဖျက်နေပါသည်"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"စာထုတ်စက်မှ အမှား <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ကိုစာထုတ်စက်ကငြင်းလိုက်သည်"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> စာထုတ်စရာများ</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>စာထုတ်စရာ</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"ပယ်ဖျက်"</string> <string name="restart" msgid="2472034227037808749">"အစက ပြန်စရန်"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"စာထုတ်စက်နဲ့ ဆက်သွယ်ထားမှု မရှိပါ"</string> diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml index c34e7bce0404..8128011e53fd 100644 --- a/packages/PrintSpooler/res/values-nb/strings.xml +++ b/packages/PrintSpooler/res/values-nb/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Skriverfeil <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Skriveren blokkerte <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> utskriftsjobber</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> utskriftsjobb</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Avbryt"</string> <string name="restart" msgid="2472034227037808749">"Start på nytt"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse med skriveren"</string> diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml index d1959d9c6393..89b2fbb8f07c 100644 --- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml +++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"रद्द गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिन्टर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिन्टर ब्लक गरियो <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> कार्यहरू प्रिन्ट गर्नुहोस्</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> कार्य प्रिन्ट गर्नुहोस्</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"रद्द गर्नुहोस्"</string> <string name="restart" msgid="2472034227037808749">"पुनःस्टार्ट गर्नुहोस्"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिन्टरमा कुनै जडान छैन"</string> diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml index 5df3298fd1aa..70b93e6df0ad 100644 --- a/packages/PrintSpooler/res/values-nl/strings.xml +++ b/packages/PrintSpooler/res/values-nl/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annuleren"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Printerfout <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> geblokkeerd door printer"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> afdruktaken</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> afdruktaak</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Annuleren"</string> <string name="restart" msgid="2472034227037808749">"Opnieuw starten"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met printer"</string> diff --git a/packages/PrintSpooler/res/values-pa-rIN/strings.xml b/packages/PrintSpooler/res/values-pa-rIN/strings.xml index 57e9969d4e7d..da819194a582 100644 --- a/packages/PrintSpooler/res/values-pa-rIN/strings.xml +++ b/packages/PrintSpooler/res/values-pa-rIN/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ਨੂੰ ਰੱਦ ਕਰ ਰਿਹਾ ਹੈ"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"ਪ੍ਰਿੰਟਰ ਅਸ਼ੁੱਧੀ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"ਪ੍ਰਿੰਟਰ ਬਲੌਕ ਕੀਤਾ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ਪ੍ਰਿੰਟ ਜੌਬਸ</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ਪ੍ਰਿੰਟ ਜੌਬਸ</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"ਰੱਦ ਕਰੋ"</string> <string name="restart" msgid="2472034227037808749">"ਰੀਸਟਾਰਟ ਕਰੋ"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"ਪ੍ਰਿੰਟਰ ਲਈ ਕੋਈ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string> diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml index 4439acb5d7bd..b7613cf63b6e 100644 --- a/packages/PrintSpooler/res/values-pl/strings.xml +++ b/packages/PrintSpooler/res/values-pl/strings.xml @@ -71,12 +71,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Anulowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Błąd drukarki: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Drukarka zablokowała <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadania drukowania</item> - <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadań drukowania</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadania drukowania</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> zadanie drukowania</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Anuluj"</string> <string name="restart" msgid="2472034227037808749">"Od nowa"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Brak połączenia z drukarką"</string> diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml index 63bb8686b725..199f304d6fc6 100644 --- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml +++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impressora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one">Tarefas de impressão <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="other">Tarefas de impressão <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Cancelar"</string> <string name="restart" msgid="2472034227037808749">"Reiniciar"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem conexão com a impressora"</string> diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml index d364ef44442c..ea94c5591b6b 100644 --- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml +++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"A cancelar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impressora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tarefas de impressão</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tarefa de impressão</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Cancelar"</string> <string name="restart" msgid="2472034227037808749">"Reiniciar"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem ligação à impressora"</string> diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml index 63bb8686b725..199f304d6fc6 100644 --- a/packages/PrintSpooler/res/values-pt/strings.xml +++ b/packages/PrintSpooler/res/values-pt/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impressora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one">Tarefas de impressão <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="other">Tarefas de impressão <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Cancelar"</string> <string name="restart" msgid="2472034227037808749">"Reiniciar"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem conexão com a impressora"</string> diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml index 51dfe7a6dc8d..1c74aab5d2b9 100644 --- a/packages/PrintSpooler/res/values-ro/strings.xml +++ b/packages/PrintSpooler/res/values-ro/strings.xml @@ -70,11 +70,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Se anulează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Eroare de printare: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printare blocată: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> activități de printare</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> de activități de printare</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> activitate de printare</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Anulați"</string> <string name="restart" msgid="2472034227037808749">"Reporniți"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Nu există conexiune la o imprimantă"</string> diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml index 6ba1046f1ddb..e900ab9793f3 100644 --- a/packages/PrintSpooler/res/values-ru/strings.xml +++ b/packages/PrintSpooler/res/values-ru/strings.xml @@ -71,12 +71,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отмена задания <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Ошибка задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Задание \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" заблокировано"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="few">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="many">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="other">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Отмена"</string> <string name="restart" msgid="2472034227037808749">"Повторить"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Нет связи с принтером"</string> diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml index 4908ea554263..5731849b146f 100644 --- a/packages/PrintSpooler/res/values-si-rLK/strings.xml +++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"අවලංගු කෙරේ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"මුද්රණ දෝෂය <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"මුද්රණ යන්ත්රය <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> අවුරා ඇති"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one">මුද්රණ කාර්ය <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="other">මුද්රණ කාර්ය <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"අවලංගු කරන්න"</string> <string name="restart" msgid="2472034227037808749">"යළි අරඹන්න"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"මුද්රණ යන්ත්රය වෙත සම්බන්ධය නැත"</string> diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml index 418363dfe4ff..1c7b740a046b 100644 --- a/packages/PrintSpooler/res/values-sk/strings.xml +++ b/packages/PrintSpooler/res/values-sk/strings.xml @@ -71,12 +71,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prebieha zrušenie úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tlačiarne – úloha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tlačiareň zablok. úlohu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tlačové úlohy</item> - <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tlačovej úlohy</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tlačových úloh</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tlačová úloha</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Zrušiť"</string> <string name="restart" msgid="2472034227037808749">"Spustiť znova"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Žiadne pripojenie k tlačiarni"</string> diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml index e2be161d5292..4c794dc895be 100644 --- a/packages/PrintSpooler/res/values-sl/strings.xml +++ b/packages/PrintSpooler/res/values-sl/strings.xml @@ -71,12 +71,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Preklic: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Napaka tiskalnika: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tiskalnik je blokiral <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalno opravilo</item> - <item quantity="two"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalni opravili</item> - <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalna opravila</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalnih opravil</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Prekliči"</string> <string name="restart" msgid="2472034227037808749">"Začni znova"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Ni povezave s tiskalnikom"</string> diff --git a/packages/PrintSpooler/res/values-sq-rAL/strings.xml b/packages/PrintSpooler/res/values-sq-rAL/strings.xml index d5ebf3266dfe..aff55f6fbe85 100644 --- a/packages/PrintSpooler/res/values-sq-rAL/strings.xml +++ b/packages/PrintSpooler/res/values-sq-rAL/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Po anulon <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri ndeshi në gabim gjatë punës: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printeri bllokoi <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> punë për printim</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> punë për printim</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Anulo"</string> <string name="restart" msgid="2472034227037808749">"Rifillo"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Printeri nuk është i lidhur"</string> diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml index 166e5dd07d4e..043048e3acb8 100644 --- a/packages/PrintSpooler/res/values-sr/strings.xml +++ b/packages/PrintSpooler/res/values-sr/strings.xml @@ -70,11 +70,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отказује се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка штампача <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Штампач је блокирао <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one">Задаци штампања <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="few">Задаци штампања <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="other">Задаци штампања <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Откажи"</string> <string name="restart" msgid="2472034227037808749">"Поново покрени"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Нема везе са штампачем"</string> diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml index 033d58359684..fd8581fd21a7 100644 --- a/packages/PrintSpooler/res/values-sv/strings.xml +++ b/packages/PrintSpooler/res/values-sv/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Skrivarfel för <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Skrivaren har blockerat <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> utskriftsjobb</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> utskriftsjobb</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Avbryt"</string> <string name="restart" msgid="2472034227037808749">"Starta om"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen anslutning till skrivaren"</string> diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml index 0e2dcdd109d2..0950f57868a5 100644 --- a/packages/PrintSpooler/res/values-sw/strings.xml +++ b/packages/PrintSpooler/res/values-sw/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Inaghairi <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Hitilafu ya kuchapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printa imefungwa <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other">Kazi ya kuchapisha ya <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="one">Kazi ya kuchapisha ya <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> </item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Ghairi"</string> <string name="restart" msgid="2472034227037808749">"Anzisha upya"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Hakuna muunganisho kwa printa"</string> diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml index 2e90d382e7f2..bf6feaec706e 100644 --- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml +++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ ரத்துசெய்கிறது"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"பிரிண்டர் பிழை <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"பிரிண்டர் <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐத் தடுத்தது"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> அச்சுப் பணிகள்</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> அச்சுப் பணி</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"ரத்துசெய்"</string> <string name="restart" msgid="2472034227037808749">"மீண்டும் தொடங்கு"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"அச்சுப்பொறியுடன் இணைக்கப்படவில்லை"</string> diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml index 6bdbd5c84139..4d14b8c80b86 100644 --- a/packages/PrintSpooler/res/values-te-rIN/strings.xml +++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను రద్దు చేస్తోంది"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"ప్రింటర్ లోపం <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"ప్రింటర్ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను బ్లాక్ చేసింది"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ముద్రణ జాబ్లు</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ముద్రణ జాబ్</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"రద్దు చేయి"</string> <string name="restart" msgid="2472034227037808749">"పునఃప్రారంభించు"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"ప్రింటర్కు కనెక్షన్ లేదు"</string> diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml index a581357dbcf7..e1f82e1bcf9e 100644 --- a/packages/PrintSpooler/res/values-th/strings.xml +++ b/packages/PrintSpooler/res/values-th/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"กำลังยกเลิก <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"ข้อผิดพลาดเครื่องพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"เครื่องพิมพ์ได้บล็อก <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> งานพิมพ์</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> งานพิมพ์</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"ยกเลิก"</string> <string name="restart" msgid="2472034227037808749">"เริ่มต้นใหม่"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"ไม่มีการเชื่อมต่อไปยังเครื่องพิมพ์"</string> diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml index 325ce8cb4983..052d8ccffa41 100644 --- a/packages/PrintSpooler/res/values-tl/strings.xml +++ b/packages/PrintSpooler/res/values-tl/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kinakansela ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Error sa printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Naka-block ang Printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ipi-print</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> na ipi-print</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Kanselahin"</string> <string name="restart" msgid="2472034227037808749">"I-restart"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Hindi nakakonekta sa printer"</string> diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml index d945979b8fe0..7f9e6f517d6a 100644 --- a/packages/PrintSpooler/res/values-tr/strings.xml +++ b/packages/PrintSpooler/res/values-tr/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> iptal ediliyor"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Yazıcı hatası: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Yazıcı <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> işini engelledi"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> yazdırma işi</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> yazdırma işi</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"İptal"</string> <string name="restart" msgid="2472034227037808749">"Yeniden başlat"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Yazıcı bağlantısı yok"</string> diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml index ffdfde068aed..d34aa2a88b4a 100644 --- a/packages/PrintSpooler/res/values-uk/strings.xml +++ b/packages/PrintSpooler/res/values-uk/strings.xml @@ -71,12 +71,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" скасовується"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Помилка завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" заблоковано"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдання друку</item> - <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдання друку</item> - <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдань друку</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдань друку</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Скасувати"</string> <string name="restart" msgid="2472034227037808749">"Перезапустити"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Немає з’єднання з принтером"</string> diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml index 72a6ab9f3c58..ccf6f56e6f31 100644 --- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml +++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> کو منسوخ کر رہا ہے"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"پرنٹر کی خرابی <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"پرنٹر نے <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> کو مسدود کر دیا"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> پرنٹ جابز</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> پرنٹ جاب</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"منسوخ کریں"</string> <string name="restart" msgid="2472034227037808749">"دوبارہ شروع کریں"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"پرنٹر کے ساتھ کوئی کنکشن نہیں ہے"</string> diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml index c7b4263e557b..d1fc47fa1263 100644 --- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml +++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bekor qilinmoqda"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Printerda xatolik: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ni taqiqladi"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> chop qilish vazifalari</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> chop qilish vazifasi</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Bekor qilish"</string> <string name="restart" msgid="2472034227037808749">"Qayta boshlash"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Printer ulanmagan"</string> diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml index 771d57c8a342..eb5de95776a5 100644 --- a/packages/PrintSpooler/res/values-vi/strings.xml +++ b/packages/PrintSpooler/res/values-vi/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hủy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Lỗi máy in <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Máy in đã chặn <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other">Lệnh in <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item> - <item quantity="one">Lệnh in <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Hủy"</string> <string name="restart" msgid="2472034227037808749">"Bắt đầu lại"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Không có kết nối nào với máy in"</string> diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml index bea91d7c2f2a..e39849ebd1c1 100644 --- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml +++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"打印机在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”时出错"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"打印机拒绝打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other">“<xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>”打印作业</item> - <item quantity="one">“<xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>”打印作业</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"取消"</string> <string name="restart" msgid="2472034227037808749">"重新开始"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"未与打印机建立连接"</string> diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml index 4fbef0dbee32..11482262cb6b 100644 --- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml +++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"打印機錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"打印機已封鎖 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> 項列印工作</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> 項列印工作</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"取消"</string> <string name="restart" msgid="2472034227037808749">"重新開始"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"尚未與打印機連線"</string> diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml index 2fdcaacb5d11..c0dd3ded7827 100644 --- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml +++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"印表機發生錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"印表機封鎖了 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> 個列印工作</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> 個列印工作</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"取消"</string> <string name="restart" msgid="2472034227037808749">"重新開始"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"尚未與印表機建立連線"</string> diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml index 92595aaba1d5..231b1bf78043 100644 --- a/packages/PrintSpooler/res/values-zu/strings.xml +++ b/packages/PrintSpooler/res/values-zu/strings.xml @@ -69,10 +69,6 @@ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ikhansela i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"Iphutha lephrinta ye-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Iphrinta engu-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ivinjelwe"</string> - <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> imisebenzi yokuphrinta</item> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> imisebenzi yokuphrinta</item> - </plurals> <string name="cancel" msgid="4373674107267141885">"Khansela"</string> <string name="restart" msgid="2472034227037808749">"Qala kabusha"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"Akukho ukuxhumana kuphrinta"</string> diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index b662c58fa122..76292a16e9b1 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -150,6 +150,9 @@ <!-- Description of printer info icon. [CHAR LIMIT=50] --> <string name="printer_info_desc">More information about this printer</string> + <!-- Notification that print services as disabled. [CHAR LIMIT=50] --> + <string name="print_services_disabled_toast">Some print services are disabled.</string> + <!-- Add printer dialog --> <!-- Title for the alert dialog for selecting a print service. [CHAR LIMIT=50] --> diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java index ea11ae40aea8..684a1de46f94 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java @@ -173,15 +173,19 @@ public final class RemotePrintDocument { if (DEBUG) { Log.i(LOG_TAG, "[CALLED] start()"); } - if (mState != STATE_INITIAL) { - throw new IllegalStateException("Cannot start in state:" + stateToString(mState)); - } - try { - mPrintDocumentAdapter.start(); - mState = STATE_STARTED; - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling start()", re); - mState = STATE_FAILED; + if (mState == STATE_FAILED) { + Log.w(LOG_TAG, "Failed before start."); + } else { + if (mState != STATE_INITIAL) { + throw new IllegalStateException("Cannot start in state:" + stateToString(mState)); + } + try { + mPrintDocumentAdapter.start(); + mState = STATE_STARTED; + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling start()", re); + mState = STATE_FAILED; + } } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java index 5525774cb2f3..cd30e263a65d 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java @@ -207,6 +207,7 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> PrinterInfo favoritePrinter = favoritePrinters.get(i).first; if (!alreadyAddedPrinter.contains(favoritePrinter.getId())) { updateAndAddPrinter(printers, favoritePrinter, discoveredPrinters); + alreadyAddedPrinter.add(favoritePrinter.getId()); } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java index 81727ab4222a..13105aa2eba0 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java @@ -65,6 +65,7 @@ import android.widget.ImageView; import android.widget.ListView; import android.widget.SearchView; import android.widget.TextView; +import android.widget.Toast; import com.android.internal.content.PackageMonitor; import com.android.printspooler.R; @@ -147,6 +148,14 @@ public final class SelectPrinterActivity extends Activity { }); registerForContextMenu(mListView); + + // Display a notification about disabled services if there are disabled services + String disabledServicesSetting = Settings.Secure.getString(getContentResolver(), + Settings.Secure.DISABLED_PRINT_SERVICES); + if (!TextUtils.isEmpty(disabledServicesSetting)) { + Toast.makeText(this, getString(R.string.print_services_disabled_toast), + Toast.LENGTH_LONG).show(); + } } @Override diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java b/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java index a1e3ef430c9e..f78115906003 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java +++ b/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java @@ -134,6 +134,11 @@ public class ApprovedPrintServices { public void pruneApprovedServices(List<ComponentName> serviceNamesToKeep) { synchronized (sLock) { Set<String> approvedServices = getApprovedServices(); + + if (approvedServices == null) { + return; + } + Set<String> newApprovedServices = new ArraySet<>(approvedServices.size()); final int numServiceNamesToKeep = serviceNamesToKeep.size(); diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 54d2dfa3c8ef..3fd4f7fb60f0 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Omogućava upisivanje svih aplikacija u spoljnu memoriju, bez obzira na vrednosti manifesta"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Prinudno omogući promenu veličine aktivnosti"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Omogućava promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore proizvoljnog formata"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogućava podršku za eksperimentalne prozore proizvoljnog formata."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka rezervne kopije za računar"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervne kopije čitavog sistema trenutno nisu zaštićene"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 95badc57f108..cd4529f111d5 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Позволява прилож. да се записват във външ. хранил. независимо от стойностите в манифеста"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Възможност за преоразмеряване на активностите"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Активиране на прозорците в свободна форма"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Активира поддръжката за експерименталните прозорци в свободна форма."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Наст. комп.: Парола"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Понастоящем пълните резервни копия за настолен компютър не са защитени"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string> diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml index e4d97d7e8516..7c598229ca4e 100644 --- a/packages/SettingsLib/res/values-bn-rBD/strings.xml +++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ম্যানিফেস্ট মানগুলি নির্বিশেষে যেকোনো অ্যাপ্লিকেশানকে বাহ্যিক সঞ্চয়স্থানে লেখার উপযুক্ত বানায়"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"আকার পরিবর্তনযোগ্য করার জন্য ক্রিয়াকলাপগুলিকে জোর করুন"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলিকে আকার পরিবর্তনযোগ্য করে তোলে৷"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"ফ্রি-ফর্ম উইন্ডোগুলি সক্ষম করুন"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ডেস্কটপ পূর্ণ ব্যাকআপ বর্তমানে সুরক্ষিত নয়"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ডেস্কটপ পুরো ব্যাকআপের জন্য পাসওয়ার্ড পরিবর্তন বা মুছে ফেলার জন্য স্পর্শ করুন"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 93b6438b37c0..1349a7aaf7ce 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet que les aplicacions es puguin escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Força l\'ajust de la mida de les activitats"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors definits."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Activa les finestres de format lliure"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activa la compatibilitat amb les finestres de format lliure experimentals."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Contrasenya per a còpies d\'ordinador"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les còpies de seguretat d\'ordinador completes no estan protegides"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca per canviar o eliminar la contrasenya per a còpies de seguretat d\'ordinador completes"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 0b1238b84ffb..4d9d4fbbc7dd 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ermöglicht es jeder qualifizierten App, Daten auf externen Speicher zu schreiben, unabhängig von den Manifestwerten"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Anpassen der Größe von Aktivitäten erzwingen"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ermöglicht es, die Größe aller Aktivitäten an den Mehrfenstermodus anzupassen, unabhängig von den Manifestwerten."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Freiform-Fenster zulassen"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Unterstützt experimentelle Freiform-Fenster."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop-Sicherungspasswort"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt."</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen berühren"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index dae40d91882c..833fb62d95ac 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index dae40d91882c..833fb62d95ac 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index dae40d91882c..833fb62d95ac 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 855b72ca97b7..4d4ab24b8e18 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Cualquier aplicación puede escribirse en una memoria externa, independientemente de los valores del manifiesto."</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Forzar actividades para que cambien de tamaño"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Habilitar ventanas de forma libre"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Habilita la admisión de ventanas de forma libre experimentales."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Contraseñas"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tus copias de seguridad de escritorio no están protegidas por contraseña."</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca para cambiar o eliminar la contraseña de las copias de seguridad completas de tu escritorio."</string> diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml index fe5fc2945e99..6405ca83d857 100644 --- a/packages/SettingsLib/res/values-eu-rES/strings.xml +++ b/packages/SettingsLib/res/values-eu-rES/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikazioek kanpoko memorian idatz dezakete, manifestuaren balioak kontuan izan gabe"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Behartu jardueren tamaina doitu ahal izatea"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifestuan jartzen duena jartzen duela ere, jarduera guztien tamaina doitzeko aukera ematen du, hainbat leihotan erabili ahal izan daitezen."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Gaitu estilo libreko leihoak"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Estilo libreko leiho esperimentalak onartzen ditu."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Tokiko babeskop. pasahitza"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Une honetan, ordenagailuko babeskopia osoak ez daude babestuta."</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Ukitu ordenagailuko babeskopia osoak egiteko pasahitza aldatzeko edo kentzeko"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index e1a35f7ba7a3..d591426d8799 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"بدون توجه به مقادیر مانیفست، هر برنامهای را برای نوشتن در حافظه خارجی واجد شرایط میکند"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"اجبار فعالیتها به قابل تغییر اندازه بودن"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"بدون درنظر گرفتن مقادیر مانیفست، همه فعالیتها را برای چندپنجره قابل تغییر اندازه میکند."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"فعال کردن پنجرههای آزاد"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"پشتیبانی برای پنجرههای آزاد آزمایشی را امکانپذیر میکند"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"گذرواژه پشتیبانگیری محلی"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"پشتیبانگیری کامل رایانه درحال حاضر محافظت نمیشود"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"برای تغییر یا حذف گذرواژه برای نسخههای پشتیبان کامل دسکتاپ لمس کنید"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 498f2045c0c8..ce36de367c53 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mahdollistaa sovellusten tallentamisen ulkoiseen tall.tilaan luettelosta riippumatta"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Pakota kaikki toiminnot hyväksymään koon muutos"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pakottaa kaikki toiminnot hyväksymään koon muuttamisen rinnakkaisnäkymään luettelon arvoista riippumatta."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Ota käyttöön vapaamuotoiset ikkunat"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ottaa käyttöön kokeellisten vapaamuotoisten ikkunoiden tuen."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Varmuuskop. salasana"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tietokoneen kaikkien tietojen varmuuskopiointia ei ole tällä hetkellä suojattu"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Muuta tai vaihda tietokoneen kaikkien tietojen varmuuskopioinnin salasana koskettamalla"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index b32bfb7eb35d..3ee07759f258 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet enreg. d\'applis sur espace stockage externe"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Forcer les activités à être redimensionnables"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Activer les fenêtres de forme libre"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Active la compatibilité avec les fenêtres de forme libre expérimentales."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 0190454e52be..c0098d240e19 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rend possible enregistrement de toute appli sur espace stockage externe, indépendamment valeurs fichier manifeste."</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Forcer possibilité de redimensionner les activités"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Activer les fenêtres de forme libre"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Active la compatibilité avec les fenêtres de forme libre expérimentales."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string> diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml index 4b72648244bb..2a0ff45f705e 100644 --- a/packages/SettingsLib/res/values-gu-rIN/strings.xml +++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml @@ -247,8 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ એપ્લિકેશનને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"પ્રવૃત્તિઓને ફરીથી કદ યોગ્ય થવા માટે ફરજ પાડો"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"તમામ પ્રવૃત્તિઓને મલ્ટી-વિંડો માટે ફરીથી કદ બદલી શકે તેવી બનાવે છે, મેનીફેસ્ટ મુલ્યોને ધ્યાનમાં લીધા સિવાય."</string> - <string name="enable_freeform_support" msgid="1461893351278940416">"મુક્તાકાર વિંડોઝ સક્ષમ કરો"</string> - <string name="enable_freeform_support_summary" msgid="2252563497485436534">"પ્રાયોગિક મુક્તાકાર વિંડોઝ માટે સમર્થનને સક્ષમ કરે છે."</string> + <string name="enable_freeform_support" msgid="1461893351278940416">"ફ્રિફોર્મ વિંડોઝ સક્ષમ કરો"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"પ્રાયોગિક ફ્રિફોર્મ વિંડોઝ માટે સમર્થનને સક્ષમ કરે છે."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"ડેસ્કટૉપ બેકઅપ પાસવર્ડ"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ હાલમાં સુરક્ષિત નથી"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ્સ માટેનો પાસવર્ડ બદલવા અથવા દૂર કરવા માટે ટચ કરો"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 5cde2332d91f..0a46b279d377 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o manifestu"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Nametni mogućnost promjene veličine za aktivnosti"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veličina svih aktivnosti može se mijenjati za više prozora, neovisno o vrijednostima manifesta."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore slobodnog oblika"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogućuje podršku za eksperimentalne prozore slobodnog oblika."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Zaporka sigurnosne kopije"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije na stolnom računalu trenutačno nisu zaštićene"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Odaberite za promjenu ili uklanjanje zaporke u potpunim sigurnosnim kopijama na stolnom računalu"</string> diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml index 42c9a05c0221..fb401f0e1415 100644 --- a/packages/SettingsLib/res/values-hy-rAM/strings.xml +++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Թույլ է տալիս պահել հավելվածը արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Ստիպել, որ ակտիվությունների չափերը լինեն փոփոխելի"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Ակտիվացնել կամայական ձևի պատուհանները"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ակտիվացնում է կամայական ձևի փորձնական պատուհանների աջակցումը:"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Աշխատասեղանի պահուստավորման գաղտնաբառ"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Աշխատասեղանի ամբողջական պահուստավորումները այժմ պաշտպանված չեն"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Աշխատասեղանի ամբողջական պահուստավորման համար ընտրել փոխել կամ հեռացնել գաղտնաբառը"</string> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 6988a732eb26..1262512210dc 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksterna"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktivitas agar ukurannya dapat diubah"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Membuat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Aktifkan jendela berformat bebas"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Mengaktifkan dukungan untuk jendela eksperimental berformat bebas."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Sandi cadangan desktop"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Saat ini cadangan desktop penuh tidak dilindungi"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Sentuh guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string> diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml index 8d912e947fc3..3e53e94df5b8 100644 --- a/packages/SettingsLib/res/values-is-rIS/strings.xml +++ b/packages/SettingsLib/res/values-is-rIS/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gerir hvaða forriti sem er kleift að skrifa í ytri geymslu, burtséð frá gildum í upplýsingaskrá"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Þvinga breytanlega stærð virkni"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gerir stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Virkja glugga með frjálsu sniði"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Kveikir á stuðningi við glugga með frjálsu sniði á tilraunastigi."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Aðgangsorð tölvuafritunar"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Heildarafritun á tölvu er ekki varin sem stendur."</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Snertu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index e175208293ce..54099c7364cc 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -190,7 +190,7 @@ <string name="hdcp_checking_title" msgid="8605478913544273282">"בדיקת HDCP"</string> <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"הגדר אופן בדיקת HDCP"</string> <string name="debug_debugging_category" msgid="6781250159513471316">"ניפוי באגים"</string> - <string name="debug_app" msgid="8349591734751384446">"בחר אפליקציה לניפוי"</string> + <string name="debug_app" msgid="8349591734751384446">"בחר אפליקציה לניפוי באגים"</string> <string name="debug_app_not_set" msgid="718752499586403499">"לא הוגדרה אפליקציה לניפוי"</string> <string name="debug_app_set" msgid="2063077997870280017">"אפליקציה לניפוי: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="select_application" msgid="5156029161289091703">"בחר אפליקציה"</string> @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"אלץ יכולת קביעת גודל של הפעילויות"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"מאפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"הפעל חלונות בצורה חופשית"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"מפעיל תמיכה בתכונה הניסיונית של חלונות בצורה חופשית."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"סיסמת גיבוי מקומי"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"גיבויים מלאים בשולחן העבודה אינם מוגנים כעת"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"גע כדי לשנות או להסיר את הסיסמה עבור גיבויים מלאים בשולחן העבודה"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index bf9bf8a44c2b..7e45fb216d1b 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"アクティビティをサイズ変更可能にする"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようになります。"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"フリーフォーム ウィンドウの有効化"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"テスト段階のフリーフォーム ウィンドウのサポートを有効にします。"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"PCバックアップパスワード"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"デスクトップのフルバックアップは現在保護されていません"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"デスクトップのフルバックアップ用のパスワードを変更または削除する場合にタップします"</string> diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml index da9d204a80f7..a8f25c6ed936 100644 --- a/packages/SettingsLib/res/values-ka-rGE/strings.xml +++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"აპები ჩაიწერ. გარე მეხს.-ზე აღწ. ფაილის მნიშვნ. მიუხედ."</string> <string name="force_resizable_activities" msgid="8615764378147824985">"ზომაცვლადი აქტივობების იძულება"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"მანიფესტის მნიშვნელობების მიუხედავად, ყველა აქტივობას მრავალი ფანჯრის რეჟიმისთვის ზომაცვლადად აქცევს."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"თავისუფალი ფორმის მქონე ფანჯრების ჩართვა"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ჩართავს თავისუფალი ფორმის მქონე ფანჯრების მხარდაჭერის ექსპერიმენტულ ფუნქციას"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"დესკტოპის სარეზერვო ასლის პაროლი"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"დესკტოპის სრული სარეზერვო ასლები ამჟამად დაცული არ არის"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string> diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml index 549711c8a283..300aaa374492 100644 --- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml +++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест мәндеріне қарамастан кез келген қолданбаны сыртқы жадқа жазуға жарамды етеді"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Әрекеттерді өлшемін өзгертуге болатын етуге мәжбүрлеу"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест мәндеріне қарамастан барлық әрекеттерді бірнеше терезе үшін өлшемін өзгертуге болатын етеді."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Еркін пішіндегі терезелерді қосу"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Эксперименттік еркін пішіндегі терезелерді қолдауды қосады."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Компьютер үстелінің сақтық көшірмесі"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Жұмыс үстелінің сақтық көшірмелері қазір қорғалмаған"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Жұмыс үстелінің толық сақтық көшірмесінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string> diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml index aed43652ae74..a414668504af 100644 --- a/packages/SettingsLib/res/values-km-rKH/strings.xml +++ b/packages/SettingsLib/res/values-km-rKH/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃជាក់លាក់"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"បង្ខំឲ្យសកម្មភាពអាចប្តូរទំហំបាន"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"កំណត់ឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុផ្ទាំងវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេសឡើយ។"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"បើកដំណើរការផ្ទាំងវិនដូទម្រង់សេរី"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"បើកដំណើរការគាំទ្រផ្ទាំងវិនដូទម្រង់សេរីសាកល្បង"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"ពាក្យសម្ងាត់បម្រុងទុកលើផ្ទៃតុ"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ការបម្រុងទុកពេញលេញលើផ្ទៃតុបច្ចុប្បន្នមិនត្រូវបានការពារទេ។"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ប៉ះ ដើម្បីប្ដូរ ឬលុបពាក្យសម្ងាត់សម្រាប់ការបម្រុងទុកពេញលេញលើផ្ទៃតុ"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index ea5dc0062f0f..c23a8a71bfb6 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"매니페스트 값에 관계없이 앱을 외부 저장소에 작성"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"활동의 크기가 조정 가능하도록 설정"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"자유 형식 창 사용"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"자유 형식 창(베타) 지원 사용"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"데스크톱 백업 비밀번호"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"데스크톱 전체 백업에 비밀번호가 설정되어 있지 않음"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"데스크톱 전체 백업에 대한 비밀번호를 변경하거나 삭제하려면 터치하세요."</string> diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml index 6a474066a166..84bfe94f0bc6 100644 --- a/packages/SettingsLib/res/values-ky-rKG/strings.xml +++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Аракеттердин өлчөмүн өзгөртүүнү мажбурлоо"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест маанилерине карабастан бардык аракеттерди мульти-терезеге өлчөмү өзгөртүлгүдөй кылат."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Эркин формадагы терезелерди түзүүнү иштетүү"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Эркин формадагы терезелерди түзүү боюнча сынамык функцияны иштетүү"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Компүтердеги бэкаптын сырсөзү"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Компүтердеги толук бэкап учурда корголгон эмес"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Тийип, компүтердеги толук бэкаптын сырсөзүн өзгөртүңүз же жок кылыңыз"</string> diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml index 538a38cb2db4..4b5359a2eb53 100644 --- a/packages/SettingsLib/res/values-lo-rLA/strings.xml +++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ເຮັດໃຫ້ທຸກແອັບມີສິດໄດ້ຮັບການຂຽນໃສ່ບ່ອນຈັດເກັບພາຍນອກ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າທີ່ຈະແຈ້ງ"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"ບັງຄັງໃຫ້ກິດຈະກຳປ່ຽນຂະໜາດໄດ້"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ເຮັດໃຫ້ທຸກກິດຈະກຳປ່ຽນຂະໜາດໄດ້ສຳລັບຫຼາຍໜ້າຕ່າງ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າທີ່ຈະແຈ້ງ."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"ເປີດໃຊ້ໜ້າຕ່າງຮູບແບບອິດສະຫຼະ"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ເປີດໃຊ້ການຮອງຮັບໜ້າຕ່າງຮູບແບບອິດສະຫຼະທີ່ທົດລອງໃຊ້."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັກສະທັອບ"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບຍັງບໍ່ໄດ້ຮັບການປ້ອງກັນໃນເວລານີ້"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ແຕະເພື່ອປ່ຽນ ຫຼືລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບ"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 014a6fb37054..6b2104144a2e 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Vis. pr. gal. įr. į vid. saug. nepais. apr. vert."</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Priv. nust., kad veiksm. b. g. atl. kelių d. lang."</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Nustatoma, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Įgalinti laisvos formos langus"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Įgalinamas eksperimentinių laisvos formos langų palaikymas."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Viet. atsrg. kop. slapt."</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Jei norite pakeisti ar pašalinti visų vietinių atsarginių kopijų slaptažodį, palieskite"</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index 87da10551316..0652b054048c 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ļauj jebkuru lietotni ierakstīt ārējā krātuvē neatkarīgi no manifesta vērtības."</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Pielāgot darbības"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pielāgo visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Iespējot brīvās formas logus"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Iespējo eksperimentālo brīvās formas logu atbalstu."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Datora dublējuma parole"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem darbvirsmas dublējumiem."</string> diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml index d76e87f7a562..2457847cc0bb 100644 --- a/packages/SettingsLib/res/values-ml-rIN/strings.xml +++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"വലിപ്പം മാറ്റാൻ പ്രവർത്തനങ്ങളെ നിർബന്ധിക്കുക"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ പ്രവർത്തനങ്ങളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലിപ്പം മാറ്റുന്നു."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"ഫ്രീഫോം വിൻഡോകൾ പ്രവർത്തനക്ഷമമാക്കുക"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"പരീക്ഷണാത്മക ഫ്രീഫോം വിൻഡോകൾക്കുള്ള പിന്തുണ പ്രവർത്തനക്ഷമമാക്കുന്നു."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"ഡെസ്ക്ടോപ്പ് ബാക്കപ്പ് പാസ്വേഡ്"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ഡെസ്ക്ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾ നിലവിൽ പരിരക്ഷിച്ചിട്ടില്ല"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ഡെസ്ക്ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾക്കായി പാസ്വേഡുകൾ മാറ്റാനോ നീക്കംചെയ്യാനോ സ്പർശിക്കുക"</string> diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml index 4aea631972fe..622c13fab2df 100644 --- a/packages/SettingsLib/res/values-mn-rMN/strings.xml +++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест утгыг нь үл хамааран дурын апп-ыг гадаад санах ойд бичих боломжтой болгодог"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааг олон цонхонд хэмжээг нь өөрчилж болохуйц болгох."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Чөлөөт хэлбэрийн цонхыг идэвхжүүлэх"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Туршилтын чөлөөт хэлбэрийн цонхны дэмжлэгийг идэвхжүүлдэг."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Десктоп нөөшлөлтийн нууц үг"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Десктоп бүрэн нөөцлөлт одоогоор хамгаалалтгүй байна"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Десктоп дээрх бүрэн нөөшлөлтийн нууц үгийг өөрчлөх буюу арилгахын тулд хүрнэ үү"</string> diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml index 1f72d04297fe..5f27232b80d1 100644 --- a/packages/SettingsLib/res/values-ms-rMY/strings.xml +++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Menjadikan sebarang apl layak ditulis ke storan luaran, walau apa juga nilai manifesnya"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktiviti supaya boleh diubah saiz"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Menjadikan semua aktiviti boleh diubah saiz untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Dayakan tetingkap bentuk bebas"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Mendayakan sokongan untuk tetingkap bentuk bebas percubaan."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Kata laluan sandaran komputer meja"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sandaran penuh komputer meja tidak dilindungi pada masa ini"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Sentuh untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh komputer meja"</string> diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml index cd4812fc32f8..0a86cdb8cae6 100644 --- a/packages/SettingsLib/res/values-my-rMM/strings.xml +++ b/packages/SettingsLib/res/values-my-rMM/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ပြနေတဲ့ တန်ဖိုး ဘယ်လိုပဲရှိနေနေ၊ ဘယ် appကို မဆို အပြင် သိုလှောင်ခန်းသို့ ရေးသားခွင့် ပေးတယ်"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"လုပ်ဆောင်ချက်များ ဆိုက်ညှိရနိုင်ရန် လုပ်ခိုင်းပါ"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"မန်နီးဖက်စ် တန်ဖိုးမရွေး၊ လုပ်ဆောင်ချက် အားလုံး ဆိုက်ညှိရနိုင်အောင် လုပ်ပေးပါ။"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"အခမဲ့ပုံစံ ဝင်းဒိုးကို ဖွင့်ပါ"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"စမ်းသပ်မှု အခမဲ့ပုံစံ ဝင်းဒိုးများအတွက် ပံ့ပိုးမှုကို ဖွင့်ပါ။"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop အရန်စကားဝှက်"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"အလုပ်ခုံတွင် အရန်သိမ်းဆည်းခြင်းများကို လောလောဆယ် မကာကွယ်နိုင်ပါ။"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"အလုပ်ခုံ တွင် အရန်သိမ်းဆည်းခြင်းအပြည့်လုပ်ရန် အတွက် စကားဝှက်ဖယ်ရန် သို့ ပြောင်းရန် တို့ထိပါ။"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index ae0b15de635b..99ee44c2ba8c 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gjør at apper kan skrives til ekstern lagring, uavhengig av manifestverdier"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til å kunne endre størrelse"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Dette gjør at alle aktivitene kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Slå på vinduer i fritt format"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Slår på støtte for vinduer i eksperimentelt fritt format."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Passord for sikkerhetskopiering på datamaskin"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Fullstendig sikkerhetskopiering på datamaskin beskyttes ikke for øyeblikket."</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string> diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml index 58855132d33e..a109197724c6 100644 --- a/packages/SettingsLib/res/values-ne-rNP/strings.xml +++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml @@ -247,8 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"म्यानिफेेस्टको उपेक्षा गरी, कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न योग्य बनाउँछ"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"गतिविधिहरू रिसाइज गर्नको लागि बाध्य गर्नुहोस्"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउँछ।"</string> - <string name="enable_freeform_support" msgid="1461893351278940416">"फ्रीफर्म विन्डोहरू सक्रिय गर्नुहोस्"</string> - <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ्रीफर्म विन्डोहरूका लागि समर्थनलाई सक्रिय गर्छ।"</string> + <string name="enable_freeform_support" msgid="1461893351278940416">"फ्रिफर्म विन्डोहरू सक्रिय गर्नुहोस्"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ्रिफर्म विन्डोहरूका लागि समर्थनलाई सक्रिय गर्छ।"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटप ब्याकअप पासवर्ड"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटप पूर्ण जगेडाहरू हाललाई सुरक्षित छैनन्"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन छुनुहोस्"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index dd4b58d51cbc..98a3121bd83e 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a senha de backups completos do desktop"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index dd4b58d51cbc..98a3121bd83e 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a senha de backups completos do desktop"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index a666da042bfb..00ff92bb2af1 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Face orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Forțați redimensionarea activităților"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Activați ferestrele cu formă liberă"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activează compatibilitatea pentru ferestrele experimentale cu formă liberă."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Parolă copie rez. desktop"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"În prezent, copiile de rezervă complete pe desktop nu sunt protejate"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Atingeţi pentru a modifica sau pentru a elimina parola pentru copiile de rezervă complete pe desktop"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index e93bae13bc98..9a3a7e6f254f 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Разрешает сохранение приложений на внешние накопители независимо от значения манифеста"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Изменение размера в многооконном режиме"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Позволяет менять размер в многооконном режиме (независимо от значений манифеста)"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Разрешить создание окон произвольной формы"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Включить экспериментальную функцию создания окон произвольной формы"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Пароль для резервного копирования"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Полные резервные копии в настоящее время не защищены"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Изменить или удалить пароль для резервного копирования"</string> diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml index 6753624a9bba..083dd05b438a 100644 --- a/packages/SettingsLib/res/values-si-rLK/strings.xml +++ b/packages/SettingsLib/res/values-si-rLK/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් අභ්යන්තර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"ක්රියාකාරකම් ප්රතිප්රමාණ කළ හැකි බවට බල කරන්න"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්රියාකාරකම් බහු-කවුළු සඳහා ප්රතිප්රමාණ කළ හැකි බවට පත් කරයි."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"අනියම් හැඩැති කවුළු සබල කරන්න"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"පරීක්ෂණාත්මක අනියම් හැඩැති කවුළු සඳහා සහාය සබල කරයි."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"ඩෙස්ක්ටොප් උපස්ථ මුරපදය"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ දැනට ආරක්ෂා කර නොමැත"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට ස්පර්ශ කරන්න"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 7db7835eda8e..e12f4357e92a 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Umožňuje zapísať akúkoľvek aplikáciu do externého úložiska bez ohľadu na hodnoty v manifeste"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Vynútiť možnosť zmeny veľkosti aktivít"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veľkosti všetkých aktivít bude možné zmeniť na niekoľko okien (bez ohľadu na hodnoty manifestu)."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Povoliť okná s voľným tvarom"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Povolenie podpory pre experimentálne okná s voľným tvarom."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pre zálohy v počítači"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy na počítači nie sú momentálne chránené"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dotykom zmeníte alebo odstránite heslo pre úplné zálohy do počítača"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index ed37933daff3..1f665831918e 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsako aplikacijo zapisati v zunanjo shrambo"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Vsili povečanje velikosti za aktivnosti"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim povečati velikost za način z več okni."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Omogočanje oken svobodne oblike"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogočanje podpore za poskusna okna svobodne oblike"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Geslo za varn. kop. rač."</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Popolne varnostne kopije namizja trenutno niso zaščitene"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dotaknite se, če želite spremeniti ali odstraniti geslo za popolno varnostno kopiranje namizja."</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 9596ce5e1caf..ab96afd6a1a8 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Принудно омогући промену величине активности"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Омогућава промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Омогући прозоре произвољног формата"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Омогућава подршку за експерименталне прозоре произвољног формата."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Лозинка резервне копије за рачунар"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Резервне копије читавог система тренутно нису заштићене"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index 7d0d0a08b0e9..f8901c94a5cc 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Appen kan skrivas till extern lagring, oavsett manifestvärden"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Framtvinga storleksanpassning för aktiviteter"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Detta gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivera frihandsfönster"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiverar stöd för experimentella frihandsfönster."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Lösenord för säkerhetskopia av datorn"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"De fullständiga säkerhetskopiorna av datorn är för närvarande inte skyddade"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tryck om du vill ändra eller ta bort lösenordet för fullständig säkerhetskopiering av datorn"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index d1041da0db20..8a33946ad7d6 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Huweka programu kwenye hifadhi ya nje, bila kujali maelezo"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Lazimisha shughuli ziweze kubadilishwa ukubwa"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwa ajili ya dirisha nyingi, bila kujali thamani za faili ya maelezo."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Washa madirisha yenye muundo huru"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Huwasha uwezo wa kutumia madirisha ya majaribio yenye muundo huru."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Nenosiri la hifadhi rudufu ya eneo kazi"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Hifadhi rudufu kamili za eneo kazi hazijalindwa kwa sasa"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Gusa ili ubadilishe au uondoe nenosiri la hifadhi rudufu kamili za eneo kazi"</string> diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml index e66f07325677..d3860391fb78 100644 --- a/packages/SettingsLib/res/values-ta-rIN/strings.xml +++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"மேனிஃபெஸ்ட் மதிப்புகளை பொருட்படுத்தாமல், எந்தப் பயன்பாட்டையும் வெளிப்புற சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமைக்கும்."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"குறிப்பிட்ட வடிவமில்லாத சாளரங்களை இயக்கு"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"பரிசோதனைக்குரிய குறிப்பிட்ட வடிவமில்லாத சாளரங்களுக்கான ஆதரவை இயக்கும்."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"டெஸ்க்டாப் காப்புப்பிரதி கடவுச்சொல்"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"டெஸ்க்டாப்பின் முழு காப்புப்பிரதிகள் தற்போது பாதுகாக்கப்படவில்லை"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"டெஸ்க்டாப்பின் முழுமையான காப்புப்பிரதிகளுக்கான கடவுச்சொல்லை மாற்றுவதற்கு அல்லது அகற்றுவதற்குத் தொடவும்"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index 6826419ce278..b17b516b3a14 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ให้สามารถเขียนแอปต่างๆ ไปยังที่เก็บภายนอกได้ โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"บังคับให้กิจกรรมปรับขนาดได้"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"เปิดใช้หน้าต่างรูปแบบอิสระ"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"เปิดการสนับสนุนหน้าต่างรูปแบบอิสระแบบทดลอง"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"รหัสผ่านการสำรองข้อมูลในเดสก์ท็อป"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป ไม่ได้รับการป้องกันในขณะนี้"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"แตะเพื่อเปลี่ยนหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 8f623268e23e..d0e7f87770c2 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mara-write na sa external storage ang anumang app, anuman ang manifest value"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Sapilitang gawing resizable ang mga aktibidad"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gawing resizable para sa multi-window ang lahat ng aktibidad, anuman ang mga manifest value."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"I-enable ang mga freeform window"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ine-enable ang suporta para sa mga pang-eksperimentong freeform window."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Password ng pag-backup ng desktop"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kasalukuyang hindi pinoprotektahan ang mga buong pag-backup ng desktop"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Pindutin upang baguhin o alisin ang password para sa mga buong pag-backup ng desktop"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 5e0839a6db10..e6ddcdd5f733 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bildirilen değerlerden bağımsız olarak uygulamaları harici depolamaya yazmak için uygun hale getirir"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Etkinlikleri yeniden boyutlandırılabilmeye zorla"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir hale getirir."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Serbest biçimli pencereleri etkinleştir"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Deneysel serbest biçimli pencereleri etkinleştirir."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü yedekleme şifresi"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için dokunun"</string> diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml index 0834303fb310..e9fe7e40a47b 100644 --- a/packages/SettingsLib/res/values-ur-rPK/strings.xml +++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"سرگرمیوں کو ری سائز ایبل بنائیں"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"manifest اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بناتا ہے۔"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"freeform ونڈوز فعال کریں"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"تجرباتی freeform ونڈوز کے لئے سپورٹ فعال کرتا ہے۔"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"ڈیسک ٹاپ کا بیک اپ پاس ورڈ"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ڈیسک ٹاپ کے مکمل بیک اپس فی الحال محفوظ کیے ہوئے نہیں ہیں"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے ٹچ کریں"</string> diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml index d2d8b76670dc..e53336b56daf 100644 --- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml +++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Manifest qiymatidan qat’i nazar istalgan ilovani tashqi xotiraga saqlash imkonini beradi"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Harakatlarni moslashuvchan o‘lchamga keltirish"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtiradi."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Erkin shakldagi oynalarni yoqish"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Tajribaviy erkin shakldagi oynalar ta’minotini yoqadi"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Zaxira nusxa uchun parol"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Ish stoli to\'liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing."</string> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index 178e301636cc..193f066ce84b 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Giúp ứng dụng bất kỳ đủ điều kiện được ghi vào bộ nhớ ngoài bất kể giá trị tệp kê khai là gì"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Buộc các hoạt động có thể thay đổi kích thước"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Giúp tất cả hoạt động có thể thay đổi kích thước cho nhiều cửa sổ bất kể giá trị tệp kê khai là gì."</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"Bật cửa sổ dạng tự do"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Bật tính năng hỗ trợ cửa sổ dạng tự do thử nghiệm."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Mật khẩu sao lưu của máy tính"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sao lưu toàn bộ máy tính hiện không được bảo vệ"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Chạm để thay đổi hoặc xóa mật khẩu dành cho bộ sao lưu toàn bộ tới máy tính"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 5b963832a61a..de8996ef5386 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"强制将活动设为可调整大小"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"将所有活动设为可配合多窗口环境调整大小(无论清单值是什么)。"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"启用可自由调整的窗口"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"启用可自由调整的窗口这一实验性功能。"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"桌面备份密码"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌面完整备份当前未设置密码保护"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"触摸可更改或删除用于桌面完整备份的密码"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index db5f09b42068..9a86f3ac88f4 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將所有應用程式寫入到外部儲存完間 (所有資訊清單值)"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"強制可變更活動尺寸"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"在任何資訊清單值下,允許為多個視窗變更所有活動的尺寸。"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"啟用自由形態視窗"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"啟用實驗版自由形態視窗的支援功能。"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"桌面電腦備份密碼"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌上電腦的完整備份目前未受保護"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"輕觸即可更改或移除桌上電腦完整備份的密碼"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 787a44218917..3ab60f5ab6ad 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -247,10 +247,8 @@ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"將活動強制設為可調整大小"</string> <string name="force_resizable_activities_summary" msgid="4508217476997182216">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string> - <!-- no translation found for enable_freeform_support (1461893351278940416) --> - <skip /> - <!-- no translation found for enable_freeform_support_summary (2252563497485436534) --> - <skip /> + <string name="enable_freeform_support" msgid="1461893351278940416">"啟用自由形式視窗"</string> + <string name="enable_freeform_support_summary" msgid="2252563497485436534">"啟用實驗版自由形式視窗的支援功能。"</string> <string name="local_backup_password_title" msgid="3860471654439418822">"電腦備份密碼"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"電腦完整備份目前未受保護"</string> <string name="local_backup_password_summary_change" msgid="2731163425081172638">"輕觸即可變更或移除電腦完整備份的密碼"</string> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index f7e25dbe5f6e..ac19cf50d62a 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -726,4 +726,41 @@ <!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] --> <string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string> + <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration --> + <string name="power_discharging_duration"><xliff:g id="level">%1$s</xliff:g> + - approx. <xliff:g id="time">%2$s</xliff:g> left</string> + + <!-- [CHAR_LIMIT=40] Label for battery level chart when charging --> + <string name="power_charging"><xliff:g id="level">%1$s</xliff:g> - + <xliff:g id="state">%2$s</xliff:g></string> + <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration --> + <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - + <xliff:g id="time">%2$s</xliff:g> until full</string> + <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration --> + <string name="power_charging_duration_ac"><xliff:g id="level">%1$s</xliff:g> - + <xliff:g id="time">%2$s</xliff:g> until full on AC</string> + <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration --> + <string name="power_charging_duration_usb"><xliff:g id="level">%1$s</xliff:g> - + <xliff:g id="time">%2$s</xliff:g> until full over USB</string> + <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration --> + <string name="power_charging_duration_wireless"><xliff:g id="level">%1$s</xliff:g> - + <xliff:g id="time">%2$s</xliff:g> until full from wireless</string> + + <!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed --> + <string name="battery_info_status_unknown">Unknown</string> + <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging from an unknown source. --> + <string name="battery_info_status_charging">Charging</string> + <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging on AC. --> + <string name="battery_info_status_charging_ac">Charging on AC</string> + <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging over USB. --> + <string name="battery_info_status_charging_usb">Charging over USB</string> + <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging over a wireless connection. --> + <string name="battery_info_status_charging_wireless">Charging wirelessly</string> + <!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed --> + <string name="battery_info_status_discharging">Not charging</string> + <!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed --> + <string name="battery_info_status_not_charging">Not charging</string> + <!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed --> + <string name="battery_info_status_full">Full</string> + </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java new file mode 100644 index 000000000000..d81bdebda33c --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java @@ -0,0 +1,107 @@ +/* + * 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.settingslib; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.BatteryManager; +import android.os.BatteryStats; +import android.os.Bundle; +import android.os.SystemClock; +import android.text.format.Formatter; +import com.android.internal.os.BatteryStatsHelper; + +public class BatteryInfo { + + public String mChargeLabelString; + public int mBatteryLevel; + public boolean mDischarging = true; + public long remainingTimeUs = 0; + + public interface Callback { + void onBatteryInfoLoaded(BatteryInfo info); + } + + public static void getBatteryInfo(final Context context, final Callback callback) { + new AsyncTask<Void, Void, BatteryStats>() { + @Override + protected BatteryStats doInBackground(Void... params) { + BatteryStatsHelper statsHelper = new BatteryStatsHelper(context, true); + statsHelper.create((Bundle) null); + return statsHelper.getStats(); + } + + @Override + protected void onPostExecute(BatteryStats batteryStats) { + final long elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000; + Intent batteryBroadcast = context.registerReceiver(null, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(context, + batteryBroadcast, batteryStats, elapsedRealtimeUs); + callback.onBatteryInfoLoaded(batteryInfo); + } + }.execute(); + } + + public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast, + BatteryStats stats, long elapsedRealtimeUs) { + BatteryInfo info = new BatteryInfo(); + info.mBatteryLevel = Utils.getBatteryLevel(batteryBroadcast); + String batteryPercentString = Utils.formatPercentage(info.mBatteryLevel); + if (batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) == 0) { + final long drainTime = stats.computeBatteryTimeRemaining(elapsedRealtimeUs); + if (drainTime > 0) { + info.remainingTimeUs = drainTime; + String timeString = Formatter.formatShortElapsedTime(context, + drainTime / 1000); + info.mChargeLabelString = context.getResources().getString( + R.string.power_discharging_duration, batteryPercentString, timeString); + } else { + info.mChargeLabelString = batteryPercentString; + } + } else { + final long chargeTime = stats.computeChargeTimeRemaining(elapsedRealtimeUs); + final String statusLabel = Utils.getBatteryStatus( + context.getResources(), batteryBroadcast); + final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS, + BatteryManager.BATTERY_STATUS_UNKNOWN); + if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) { + info.mDischarging = false; + info.remainingTimeUs = chargeTime; + String timeString = Formatter.formatShortElapsedTime(context, + chargeTime / 1000); + int plugType = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); + int resId; + if (plugType == BatteryManager.BATTERY_PLUGGED_AC) { + resId = R.string.power_charging_duration_ac; + } else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) { + resId = R.string.power_charging_duration_usb; + } else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) { + resId = R.string.power_charging_duration_wireless; + } else { + resId = R.string.power_charging_duration; + } + info.mChargeLabelString = context.getResources().getString( + resId, batteryPercentString, timeString); + } else { + info.mChargeLabelString = context.getResources().getString( + R.string.power_charging, batteryPercentString, statusLabel); + } + } + return info; + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index 621a09cdfa37..72df96d65637 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -1,17 +1,21 @@ package com.android.settingslib; import android.content.Context; +import android.content.Intent; import android.content.pm.UserInfo; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; +import android.os.BatteryManager; import android.os.UserManager; - import com.android.internal.util.UserIcons; import com.android.settingslib.drawable.CircleFramedDrawable; -public final class Utils { +import java.text.NumberFormat; + +public class Utils { /** * Return string resource that best describes combination of tethering @@ -81,4 +85,57 @@ public final class Utils { return CircleFramedDrawable.getInstance(context, UserIcons.convertToBitmap( UserIcons.getDefaultUserIcon(user.id, /* light= */ false))); } + + /** Formats the ratio of amount/total as a percentage. */ + public static String formatPercentage(long amount, long total) { + return formatPercentage(((double) amount) / total); + } + + /** Formats an integer from 0..100 as a percentage. */ + public static String formatPercentage(int percentage) { + return formatPercentage(((double) percentage) / 100.0); + } + + /** Formats a double from 0.0..1.0 as a percentage. */ + private static String formatPercentage(double percentage) { + return NumberFormat.getPercentInstance().format(percentage); + } + + public static int getBatteryLevel(Intent batteryChangedIntent) { + int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); + int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 100); + return (level * 100) / scale; + } + + public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) { + final Intent intent = batteryChangedIntent; + + int plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, + BatteryManager.BATTERY_STATUS_UNKNOWN); + String statusString; + if (status == BatteryManager.BATTERY_STATUS_CHARGING) { + int resId; + if (plugType == BatteryManager.BATTERY_PLUGGED_AC) { + resId = R.string.battery_info_status_charging_ac; + } else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) { + resId = R.string.battery_info_status_charging_usb; + } else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) { + resId = R.string.battery_info_status_charging_wireless; + } else { + resId = R.string.battery_info_status_charging; + } + statusString = res.getString(resId); + } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) { + statusString = res.getString(R.string.battery_info_status_discharging); + } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) { + statusString = res.getString(R.string.battery_info_status_not_charging); + } else if (status == BatteryManager.BATTERY_STATUS_FULL) { + statusString = res.getString(R.string.battery_info_status_full); + } else { + statusString = res.getString(R.string.battery_info_status_unknown); + } + + return statusString; + } } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 9546c8dba734..6201fd6632cd 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -58,6 +58,7 @@ <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" /> <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" /> <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> + <uses-permission android:name="android.permission.TETHER_PRIVILEGED" /> <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" /> <uses-permission android:name="android.permission.CONTROL_VPN" /> <uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/> @@ -142,6 +143,9 @@ <!-- Block notifications inline notifications --> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> + <!-- Access battery information --> + <uses-permission android:name="android.permission.BATTERY_STATS" /> + <application android:name=".SystemUIApplication" android:persistent="true" diff --git a/packages/SystemUI/res/layout/battery_detail.xml b/packages/SystemUI/res/layout/battery_detail.xml new file mode 100644 index 000000000000..ea4db4b14182 --- /dev/null +++ b/packages/SystemUI/res/layout/battery_detail.xml @@ -0,0 +1,64 @@ +<?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. +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="16dp" + android:background="?android:attr/selectableItemBackground" + android:clickable="true"> + + <ImageView + android:id="@android:id/icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:scaleType="fitCenter" + android:adjustViewBounds="true" + android:layout_alignParentTop="true" + android:layout_alignParentStart="true" + android:layout_marginStart="16dp" + android:layout_marginEnd="32dp" /> + + <TextView + android:id="@android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toStartOf="@android:id/toggle" + android:layout_toEndOf="@android:id/icon" + android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" + android:text="@string/battery_detail_switch_title" /> + + <TextView + android:id="@android:id/summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@android:id/title" + android:layout_toStartOf="@android:id/toggle" + android:layout_toEndOf="@android:id/icon" + android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" + android:text="@string/battery_detail_switch_summary" /> + + <Switch + android:id="@android:id/toggle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentTop="true" + android:layout_marginEnd="16dp" + android:clickable="false" + android:textAppearance="@style/TextAppearance.QS.DetailHeader" /> + +</RelativeLayout> diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml index 7ac9c41fe208..39da8d02a855 100644 --- a/packages/SystemUI/res/layout/super_status_bar.xml +++ b/packages/SystemUI/res/layout/super_status_bar.xml @@ -84,16 +84,10 @@ android:layout_width="match_parent" android:layout_height="match_parent"/> - <com.android.systemui.statusbar.phone.PanelHolder - android:id="@+id/panel_holder" + <include layout="@layout/status_bar_expanded" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/transparent" > - <include layout="@layout/status_bar_expanded" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - </com.android.systemui.statusbar.phone.PanelHolder> + android:visibility="gone" /> <com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_in_front" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index bb8f4adf70e1..1e2dba35ef38 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -77,7 +77,7 @@ <string name="usb_preference_title" msgid="6551050377388882787">"USB文件传输选项"</string> <string name="use_mtp_button_title" msgid="4333504413563023626">"作为媒体播放器(MTP)装载"</string> <string name="use_ptp_button_title" msgid="7517127540301625751">"作为相机(PTP)装载"</string> - <string name="installer_cd_button_title" msgid="2312667578562201583">"安装适用于Mac的Android文件传输应用"</string> + <string name="installer_cd_button_title" msgid="2312667578562201583">"安装适用于 Mac 的 Android 文件传输应用"</string> <string name="accessibility_back" msgid="567011538994429120">"返回"</string> <string name="accessibility_home" msgid="8217216074895377641">"主屏幕"</string> <string name="accessibility_menu" msgid="316839303324695949">"菜单"</string> @@ -460,10 +460,8 @@ <string name="notification_importance_default" msgid="4926529615920610817">"显示这些通知,但不发出提示音"</string> <string name="notification_importance_high" msgid="3222680136612408223">"在通知列表顶部显示,并发出提示音"</string> <string name="notification_importance_max" msgid="5236987171904756134">"在屏幕上持续显示,并发出提示音"</string> - <!-- no translation found for notification_more_settings (816306283396553571) --> - <skip /> - <!-- no translation found for notification_done (5279426047273930175) --> - <skip /> + <string name="notification_more_settings" msgid="816306283396553571">"更多设置"</string> + <string name="notification_done" msgid="5279426047273930175">"完成"</string> <string name="color_matrix_none" msgid="2121957926040543148">"常规颜色"</string> <string name="color_matrix_night" msgid="5943817622105307072">"夜间颜色"</string> <string name="color_matrix_custom" msgid="3655576492322298713">"自定义颜色"</string> diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml index 6102aa6e1a97..bf0cba22ab0c 100644 --- a/packages/SystemUI/res/values/arrays.xml +++ b/packages/SystemUI/res/values/arrays.xml @@ -37,4 +37,18 @@ <item>157</item><item>334</item> <item>0</item> <item>334</item> </array> + <array name="batterymeter_plus_points"> + <item>3</item><item>0</item> + <item>5</item><item>0</item> + <item>5</item><item>3</item> + <item>8</item><item>3</item> + <item>8</item><item>5</item> + <item>5</item><item>5</item> + <item>5</item><item>8</item> + <item>3</item><item>8</item> + <item>3</item><item>5</item> + <item>0</item><item>5</item> + <item>0</item><item>3</item> + <item>3</item><item>3</item> + </array> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 0ccc236aee8b..905da1388f4c 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -62,8 +62,6 @@ <color name="recents_task_bar_light_icon_color">#ffeeeeee</color> <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. --> <color name="recents_task_bar_dark_icon_color">#99000000</color> - <!-- The recents task bar highlight color. --> - <color name="recents_task_bar_highlight_color">#28ffffff</color> <!-- The lock to task button background color. --> <color name="recents_task_view_lock_to_app_button_background_color">#ffe6e6e6</color> <!-- The lock to task button foreground color. --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 035f56485287..097c35266f98 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -198,16 +198,16 @@ <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen> <!-- The min translation in the Z index for the last task. --> - <dimen name="recents_task_view_z_min">20dp</dimen> + <dimen name="recents_task_view_z_min">16dp</dimen> <!-- The max translation in the Z index for the last task. --> - <dimen name="recents_task_view_z_max">80dp</dimen> + <dimen name="recents_task_view_z_max">48dp</dimen> <!-- The amount to translate when animating the removal of a task. --> <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen> <!-- The amount of highlight to make on each task view. --> - <dimen name="recents_task_view_highlight">1.5dp</dimen> + <dimen name="recents_task_view_highlight">1dp</dimen> <!-- The amount to offset when animating into an affiliate group. --> <dimen name="recents_task_view_affiliate_group_enter_offset">64dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 876c21efe1a8..4136c110c649 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1269,4 +1269,16 @@ <string name="color_modification_g" translatable="false">G</string> <string name="color_modification_b" translatable="false">B</string> + <!-- Title of the battery settings detail panel [CHAR LIMIT=20] --> + <string name="battery_panel_title">Battery (<xliff:g name="pattery_percent" example="52">%1$d</xliff:g>%%)</string> + + <!-- Summary of battery saver not available [CHAR LIMIT=NONE] --> + <string name="battery_detail_charging_summary">Battery Saver not available during charging</string> + + <!-- Title of switch for battery saver [CHAR LIMIT=NONE] --> + <string name="battery_detail_switch_title">Battery Saver</string> + + <!-- Summary of switch for battery saver [CHAR LIMIT=NONE] --> + <string name="battery_detail_switch_summary">Reduces performance and background data</string> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java index 3eb12711d1a2..38ae345ea53e 100755 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java @@ -49,7 +49,8 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, private float mButtonHeightFraction; private float mSubpixelSmoothingLeft; private float mSubpixelSmoothingRight; - private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint; + private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint, + mPlusPaint; private float mTextHeight, mWarningTextHeight; private int mIconTint = Color.WHITE; @@ -60,10 +61,13 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, private int mChargeColor; private final float[] mBoltPoints; private final Path mBoltPath = new Path(); + private final float[] mPlusPoints; + private final Path mPlusPath = new Path(); private final RectF mFrame = new RectF(); private final RectF mButtonFrame = new RectF(); private final RectF mBoltFrame = new RectF(); + private final RectF mPlusFrame = new RectF(); private final Path mShapePath = new Path(); private final Path mClipPath = new Path(); @@ -141,6 +145,9 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color)); mBoltPoints = loadBoltPoints(res); + mPlusPaint = new Paint(mBoltPaint); + mPlusPoints = loadPlusPoints(res); + mDarkModeBackgroundColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_background); mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill); @@ -187,8 +194,8 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, } @Override - public void onPowerSaveChanged() { - mPowerSaveEnabled = mBatteryController.isPowerSave(); + public void onPowerSaveChanged(boolean isPowerSave) { + mPowerSaveEnabled = isPowerSave; invalidateSelf(); } @@ -207,6 +214,21 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, return ptsF; } + private static float[] loadPlusPoints(Resources res) { + final int[] pts = res.getIntArray(R.array.batterymeter_plus_points); + int maxX = 0, maxY = 0; + for (int i = 0; i < pts.length; i += 2) { + maxX = Math.max(maxX, pts[i]); + maxY = Math.max(maxY, pts[i + 1]); + } + final float[] ptsF = new float[pts.length]; + for (int i = 0; i < pts.length; i += 2) { + ptsF[i] = (float)pts[i] / maxX; + ptsF[i + 1] = (float)pts[i + 1] / maxY; + } + return ptsF; + } + @Override public void setBounds(int left, int top, int right, int bottom) { super.setBounds(left, top, right, bottom); @@ -328,9 +350,9 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, if (mPluggedIn) { // define the bolt shape - final float bl = mFrame.left + mFrame.width() / 4.5f; + final float bl = mFrame.left + mFrame.width() / 4f; final float bt = mFrame.top + mFrame.height() / 6f; - final float br = mFrame.right - mFrame.width() / 7f; + final float br = mFrame.right - mFrame.width() / 4f; final float bb = mFrame.bottom - mFrame.height() / 10f; if (mBoltFrame.left != bl || mBoltFrame.top != bt || mBoltFrame.right != br || mBoltFrame.bottom != bb) { @@ -358,6 +380,39 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, // otherwise cut the bolt out of the overall shape mShapePath.op(mBoltPath, Path.Op.DIFFERENCE); } + } else if (mPowerSaveEnabled) { + // define the plus shape + final float pw = mFrame.width() * 2 / 3; + final float pl = mFrame.left + (mFrame.width() - pw) / 2; + final float pt = mFrame.top + (mFrame.height() - pw) / 2; + final float pr = mFrame.right - (mFrame.width() - pw) / 2; + final float pb = mFrame.bottom - (mFrame.height() - pw) / 2; + if (mPlusFrame.left != pl || mPlusFrame.top != pt + || mPlusFrame.right != pr || mPlusFrame.bottom != pb) { + mPlusFrame.set(pl, pt, pr, pb); + mPlusPath.reset(); + mPlusPath.moveTo( + mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(), + mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height()); + for (int i = 2; i < mPlusPoints.length; i += 2) { + mPlusPath.lineTo( + mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(), + mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height()); + } + mPlusPath.lineTo( + mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(), + mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height()); + } + + float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top); + boltPct = Math.min(Math.max(boltPct, 0), 1); + if (boltPct <= BOLT_LEVEL_THRESHOLD) { + // draw the bolt if opaque + c.drawPath(mPlusPath, mPlusPaint); + } else { + // otherwise cut the bolt out of the overall shape + mShapePath.op(mPlusPath, Path.Op.DIFFERENCE); + } } // compute percentage text diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 6cb8da4a1016..cdbdc229d443 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -74,7 +74,7 @@ public class BatteryMeterView extends ImageView implements BatteryController.Bat } @Override - public void onPowerSaveChanged() { + public void onPowerSaveChanged(boolean isPowerSave) { } diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java index 7f6cda036515..99028a6c403f 100644 --- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java @@ -32,7 +32,7 @@ public interface RecentsComponent { /** * Docks the top-most task and opens recents. */ - void dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds); + boolean dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds); /** * Called during a drag-from-navbar-in gesture. diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index 19b65f77da30..ea1c9bf3b853 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -52,7 +52,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private static final int SHOWING_NOTHING = 0; private static final int SHOWING_WARNING = 1; - private static final int SHOWING_SAVER = 2; private static final int SHOWING_INVALID_CHARGER = 3; private static final String[] SHOWING_STRINGS = { "SHOWING_NOTHING", @@ -63,7 +62,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings"; private static final String ACTION_START_SAVER = "PNW.startSaver"; - private static final String ACTION_STOP_SAVER = "PNW.stopSaver"; private static final String ACTION_DISMISSED_WARNING = "PNW.dismissedWarning"; private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder() @@ -77,7 +75,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private final Handler mHandler = new Handler(); private final Receiver mReceiver = new Receiver(); private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY); - private final Intent mOpenSaverSettings = settings(Settings.ACTION_BATTERY_SAVER_SETTINGS); private int mBatteryLevel; private int mBucket; @@ -86,7 +83,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private long mBucketDroppedNegativeTimeMs; - private boolean mSaver; private boolean mWarning; private boolean mPlaySound; private boolean mInvalidCharger; @@ -101,7 +97,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { @Override public void dump(PrintWriter pw) { - pw.print("mSaver="); pw.println(mSaver); pw.print("mWarning="); pw.println(mWarning); pw.print("mPlaySound="); pw.println(mPlaySound); pw.print("mInvalidCharger="); pw.println(mInvalidCharger); @@ -121,27 +116,15 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { mScreenOffTime = screenOffTime; } - @Override - public void showSaverMode(boolean mode) { - mSaver = mode; - if (mSaver && mSaverConfirmation != null) { - mSaverConfirmation.dismiss(); - } - updateNotification(); - } - private void updateNotification() { if (DEBUG) Slog.d(TAG, "updateNotification mWarning=" + mWarning + " mPlaySound=" - + mPlaySound + " mSaver=" + mSaver + " mInvalidCharger=" + mInvalidCharger); + + mPlaySound + " mInvalidCharger=" + mInvalidCharger); if (mInvalidCharger) { showInvalidChargerNotification(); mShowing = SHOWING_INVALID_CHARGER; } else if (mWarning) { showWarningNotification(); mShowing = SHOWING_WARNING; - } else if (mSaver) { - showSaverNotification(); - mShowing = SHOWING_SAVER; } else { mNoMan.cancelAsUser(TAG_NOTIFICATION, R.id.notification_power, UserHandle.ALL); mShowing = SHOWING_NOTHING; @@ -165,8 +148,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } private void showWarningNotification() { - final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started - : R.string.battery_low_percent_format; + final int textRes = R.string.battery_low_percent_format; final String percentage = NumberFormat.getPercentInstance().format((double) mBatteryLevel / 100.0); final Notification.Builder nb = new Notification.Builder(mContext) .setSmallIcon(R.drawable.ic_power_low) @@ -184,13 +166,9 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { if (hasBatterySettings()) { nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS)); } - if (!mSaver) { - nb.addAction(0, - mContext.getString(R.string.battery_saver_start_action), - pendingBroadcast(ACTION_START_SAVER)); - } else { - addStopSaverAction(nb); - } + nb.addAction(0, + mContext.getString(R.string.battery_saver_start_action), + pendingBroadcast(ACTION_START_SAVER)); if (mPlaySound) { attachLowBatterySound(nb); mPlaySound = false; @@ -199,35 +177,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, n, UserHandle.ALL); } - private void showSaverNotification() { - final Notification.Builder nb = new Notification.Builder(mContext) - .setSmallIcon(R.drawable.ic_power_saver) - .setContentTitle(mContext.getString(R.string.battery_saver_notification_title)) - .setContentText(mContext.getString(R.string.battery_saver_notification_text)) - .setOngoing(true) - .setShowWhen(false) - .setVisibility(Notification.VISIBILITY_PUBLIC) - .setColor(mContext.getColor( - com.android.internal.R.color.battery_saver_mode_color)); - addStopSaverAction(nb); - if (hasSaverSettings()) { - nb.setContentIntent(pendingActivity(mOpenSaverSettings)); - } - mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, nb.build(), UserHandle.ALL); - } - - private void addStopSaverAction(Notification.Builder nb) { - nb.addAction(0, - mContext.getString(R.string.battery_saver_notification_action_text), - pendingBroadcast(ACTION_STOP_SAVER)); - } - - private void dismissSaverNotification() { - if (mSaver) Slog.i(TAG, "dismissing saver notification"); - mSaver = false; - updateNotification(); - } - private PendingIntent pendingActivity(Intent intent) { return PendingIntent.getActivityAsUser(mContext, 0, intent, 0, null, UserHandle.CURRENT); @@ -272,10 +221,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { return mOpenBatterySettings.resolveActivity(mContext.getPackageManager()) != null; } - private boolean hasSaverSettings() { - return mOpenSaverSettings.resolveActivity(mContext.getPackageManager()) != null; - } - @Override public void showLowBatteryWarning(boolean playSound) { Slog.i(TAG, @@ -367,7 +312,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_SHOW_BATTERY_SETTINGS); filter.addAction(ACTION_START_SAVER); - filter.addAction(ACTION_STOP_SAVER); filter.addAction(ACTION_DISMISSED_WARNING); mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, android.Manifest.permission.STATUS_BAR_SERVICE, mHandler); @@ -383,10 +327,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } else if (action.equals(ACTION_START_SAVER)) { dismissLowBatteryNotification(); showStartSaverConfirmation(); - } else if (action.equals(ACTION_STOP_SAVER)) { - dismissSaverNotification(); - dismissLowBatteryNotification(); - setSaverMode(false); } else if (action.equals(ACTION_DISMISSED_WARNING)) { dismissLowBatteryWarning(); } diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index 945974042edf..522d5338461f 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -76,10 +76,6 @@ public class PowerUI extends SystemUI { mReceiver.init(); } - private void setSaverMode(boolean mode) { - mWarnings.showSaverMode(mode); - } - void updateBatteryWarningLevels() { int critLevel = mContext.getResources().getInteger( com.android.internal.R.integer.config_criticalBatteryWarningLevel); @@ -141,11 +137,6 @@ public class PowerUI extends SystemUI { filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); mContext.registerReceiver(this, filter, null, mHandler); - updateSaverMode(); - } - - private void updateSaverMode() { - setSaverMode(mPowerManager.isPowerSaveMode()); } @Override @@ -210,10 +201,6 @@ public class PowerUI extends SystemUI { mScreenOffTime = -1; } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { mWarnings.userSwitched(); - } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) { - updateSaverMode(); - } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) { - setSaverMode(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false)); } else { Slog.w(TAG, "unknown intent: " + intent); } @@ -251,7 +238,6 @@ public class PowerUI extends SystemUI { public interface WarningsUI { void update(int batteryLevel, int bucket, long screenOffTime); - void showSaverMode(boolean mode); void dismissLowBatteryWarning(); void showLowBatteryWarning(boolean playSound); void dismissInvalidChargerWarning(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 16fd9ebba7fd..91f88b9b6736 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -466,7 +466,7 @@ public class QSPanel extends FrameLayout implements Tunable { MetricsLogger.visible(mContext, detailAdapter.getMetricsCategory()); announceForAccessibility(mContext.getString( R.string.accessibility_quick_settings_detail, - mContext.getString(detailAdapter.getTitle()))); + detailAdapter.getTitle())); setDetailRecord(r); listener = mHideGridContentWhenDone; if (r instanceof TileRecord && visibleDiff) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index b6776bba0aff..8ce6da2eede9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -109,7 +109,7 @@ public abstract class QSTile<TState extends State> implements Listenable { } public interface DetailAdapter { - int getTitle(); + CharSequence getTitle(); Boolean getToggleState(); View createDetailView(Context context, View convertView, ViewGroup parent); Intent getSettingsIntent(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java index 84eac65a54e7..60238fc3af6b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java @@ -19,7 +19,14 @@ import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Checkable; +import android.widget.ImageView; +import android.widget.TextView; import com.android.internal.logging.MetricsLogger; +import com.android.settingslib.BatteryInfo; import com.android.systemui.BatteryMeterDrawable; import com.android.systemui.R; import com.android.systemui.qs.QSTile; @@ -31,8 +38,11 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll private final BatteryMeterDrawable mDrawable; private final BatteryController mBatteryController; + private final BatteryDetail mBatteryDetail = new BatteryDetail(); private int mLevel; + private boolean mPowerSave; + private boolean mCharging; public BatteryTile(Host host) { super(host); @@ -48,6 +58,11 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll } @Override + public DetailAdapter getDetailAdapter() { + return mBatteryDetail; + } + + @Override public int getMetricsCategory() { return MetricsLogger.QS_BATTERY_TILE; } @@ -64,8 +79,16 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll } @Override + public void setDetailListening(boolean listening) { + super.setDetailListening(listening); + if (!listening) { + mBatteryDetail.mCurrentView = null; + } + } + + @Override protected void handleClick() { - mHost.startActivityDismissingKeyguard(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY)); + showDetail(true); } @Override @@ -85,11 +108,98 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { mLevel = level; + mCharging = charging; refreshState((Integer) level); + if (mBatteryDetail.mCurrentView != null) { + mBatteryDetail.bindView(); + } } @Override - public void onPowerSaveChanged() { + public void onPowerSaveChanged(boolean isPowerSave) { + mPowerSave = isPowerSave; + if (mBatteryDetail.mCurrentView != null) { + mBatteryDetail.bindView(); + } + } + + private final class BatteryDetail implements DetailAdapter, View.OnClickListener { + private final BatteryMeterDrawable mDrawable = new BatteryMeterDrawable(mHost.getContext(), + new Handler(), mHost.getContext().getColor(R.color.batterymeter_frame_color)); + private View mCurrentView; + + @Override + public CharSequence getTitle() { + return mContext.getString(R.string.battery_panel_title, mLevel); + } + + @Override + public Boolean getToggleState() { + return null; + } + + @Override + public View createDetailView(Context context, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(mContext).inflate(R.layout.battery_detail, parent, + false); + } + mCurrentView = convertView; + bindView(); + return convertView; + } + + private void bindView() { + mDrawable.onBatteryLevelChanged(100, false, false); + mDrawable.onPowerSaveChanged(true); + ((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable); + Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle); + checkbox.setChecked(mPowerSave); + if (mCharging) { + BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() { + @Override + public void onBatteryInfoLoaded(BatteryInfo info) { + if (mCurrentView != null && mCharging) { + ((TextView) mCurrentView.findViewById(android.R.id.title)).setText( + info.mChargeLabelString); + } + } + }); + ((TextView) mCurrentView.findViewById(android.R.id.summary)).setText( + R.string.battery_detail_charging_summary); + mCurrentView.setClickable(false); + mCurrentView.findViewById(android.R.id.icon).setVisibility(View.INVISIBLE); + mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.INVISIBLE); + } else { + ((TextView) mCurrentView.findViewById(android.R.id.title)).setText( + R.string.battery_detail_switch_title); + ((TextView) mCurrentView.findViewById(android.R.id.summary)).setText( + R.string.battery_detail_switch_summary); + mCurrentView.setClickable(true); + mCurrentView.findViewById(android.R.id.icon).setVisibility(View.VISIBLE); + mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.VISIBLE); + mCurrentView.setOnClickListener(this); + } + } + @Override + public void onClick(View v) { + mBatteryController.setPowerSaveMode(!mPowerSave); + } + + @Override + public Intent getSettingsIntent() { + return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY); + } + + @Override + public void setToggleState(boolean state) { + // No toggle state. + } + + @Override + public int getMetricsCategory() { + return MetricsLogger.QS_BATTERY_DETAIL; + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index cfc09a0153bf..37502904ce6b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -165,8 +165,8 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> { private QSDetailItems mItems; @Override - public int getTitle() { - return R.string.quick_settings_bluetooth_label; + public CharSequence getTitle() { + return mContext.getString(R.string.quick_settings_bluetooth_label); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index a8e139c1cd43..de4c21cd1580 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -160,8 +160,8 @@ public class CastTile extends QSTile<QSTile.BooleanState> { private QSDetailItems mItems; @Override - public int getTitle() { - return R.string.quick_settings_cast_title; + public CharSequence getTitle() { + return mContext.getString(R.string.quick_settings_cast_title); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 6c7b33730eec..c1dcfea8ca01 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -223,8 +223,8 @@ public class CellularTile extends QSTile<QSTile.SignalState> { private final class CellularDetailAdapter implements DetailAdapter { @Override - public int getTitle() { - return R.string.quick_settings_cellular_detail_title; + public CharSequence getTitle() { + return mContext.getString(R.string.quick_settings_cellular_detail_title); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index 4f9f46df7d26..4d9b266a3513 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -218,8 +218,8 @@ public class DndTile extends QSTile<QSTile.BooleanState> { private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener { @Override - public int getTitle() { - return R.string.quick_settings_dnd_label; + public CharSequence getTitle() { + return mContext.getString(R.string.quick_settings_dnd_label); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 48b4096c8500..95ea3f886e09 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -240,8 +240,8 @@ public class WifiTile extends QSTile<QSTile.SignalState> { private AccessPoint[] mAccessPoints; @Override - public int getTitle() { - return R.string.quick_settings_wifi_label; + public CharSequence getTitle() { + return mContext.getString(R.string.quick_settings_wifi_label); } public Intent getSettingsIntent() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index b81c23a6e0a7..2baefd57b0cc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -17,6 +17,7 @@ package com.android.systemui.recents; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; @@ -205,7 +206,7 @@ public class Recents extends SystemUI public void showRecents(boolean triggeredFromAltTab, View statusBarView) { // Ensure the device has been provisioned before allowing the user to interact with // recents - if (!isDeviceProvisioned()) { + if (!isUserSetup()) { return; } @@ -242,7 +243,7 @@ public class Recents extends SystemUI public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { // Ensure the device has been provisioned before allowing the user to interact with // recents - if (!isDeviceProvisioned()) { + if (!isUserSetup()) { return; } @@ -277,7 +278,7 @@ public class Recents extends SystemUI public void toggleRecents(Display display, int layoutDirection, View statusBarView) { // Ensure the device has been provisioned before allowing the user to interact with // recents - if (!isDeviceProvisioned()) { + if (!isUserSetup()) { return; } @@ -312,7 +313,7 @@ public class Recents extends SystemUI public void preloadRecents() { // Ensure the device has been provisioned before allowing the user to interact with // recents - if (!isDeviceProvisioned()) { + if (!isUserSetup()) { return; } @@ -340,7 +341,7 @@ public class Recents extends SystemUI public void cancelPreloadingRecents() { // Ensure the device has been provisioned before allowing the user to interact with // recents - if (!isDeviceProvisioned()) { + if (!isUserSetup()) { return; } @@ -365,11 +366,20 @@ public class Recents extends SystemUI } @Override - public void dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) { - mImpl.dockTopTask(draggingInRecents, stackCreateMode,initialBounds); - if (draggingInRecents) { - mDraggingInRecentsCurrentUser = sSystemServicesProxy.getCurrentUser(); + public boolean dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) { + // Ensure the device has been provisioned before allowing the user to interact with + // recents + if (!isUserSetup()) { + return false; } + + if (mImpl.dockTopTask(draggingInRecents, stackCreateMode,initialBounds)) { + if (draggingInRecents) { + mDraggingInRecentsCurrentUser = sSystemServicesProxy.getCurrentUser(); + } + return true; + } + return false; } @Override @@ -422,7 +432,7 @@ public class Recents extends SystemUI public void showNextAffiliatedTask() { // Ensure the device has been provisioned before allowing the user to interact with // recents - if (!isDeviceProvisioned()) { + if (!isUserSetup()) { return; } @@ -433,7 +443,7 @@ public class Recents extends SystemUI public void showPrevAffiliatedTask() { // Ensure the device has been provisioned before allowing the user to interact with // recents - if (!isDeviceProvisioned()) { + if (!isUserSetup()) { return; } @@ -559,11 +569,12 @@ public class Recents extends SystemUI } /** - * @return whether this device is provisioned. + * @return whether this device is provisioned and the current user is set up. */ - private boolean isDeviceProvisioned() { - return Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.DEVICE_PROVISIONED, 0) != 0; + private boolean isUserSetup() { + ContentResolver cr = mContext.getContentResolver(); + return (Settings.Global.getInt(cr, Settings.Global.DEVICE_PROVISIONED, 0) != 0) && + (Settings.Secure.getInt(cr, Settings.Secure.USER_SETUP_COMPLETE, 0) != 0); } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 213018a50b2c..ddeb8dcecf17 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -76,8 +76,6 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements ActivityOptions.OnAnimationFinishedListener { private final static String TAG = "RecentsImpl"; - private final static boolean DEBUG = false; - // The minimum amount of time between each recents button press that we will handle private final static int MIN_TOGGLE_DELAY_MS = 350; // The duration within which the user releasing the alt tab (from when they pressed alt tab) @@ -186,8 +184,6 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements mContext = context; mHandler = new Handler(); mAppWidgetHost = new RecentsAppWidgetHost(mContext, RecentsAppWidgetHost.HOST_ID); - Resources res = mContext.getResources(); - LayoutInflater inflater = LayoutInflater.from(mContext); // Initialize the static foreground thread ForegroundThread.get(); @@ -198,14 +194,8 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements ssp.registerTaskStackListener(mTaskStackListener); // Initialize the static configuration resources - mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); - mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height); - mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width); - mTaskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height); - mDummyStackView = new TaskStackView(mContext, new TaskStack()); - mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header, - null, false); - reloadHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); + reloadHeaderBarLayout(); + updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); // 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. @@ -221,11 +211,12 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements public void onBootCompleted() { mBootCompleted = true; - reloadHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); + updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); } - @Override public void onConfigurationChanged() { + reloadHeaderBarLayout(); + updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); // Don't reuse task stack views if the configuration changes mCanReuseTaskStackViews = false; Recents.getConfiguration().updateOnConfigurationChange(); @@ -257,7 +248,6 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements } } - @Override public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents, boolean animate, boolean reloadTasks) { mTriggeredFromAltTab = triggeredFromAltTab; @@ -300,7 +290,6 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements } } - @Override public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { if (mBootCompleted) { if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) { @@ -321,7 +310,6 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements } } - @Override public void toggleRecents() { // Skip this toggle if we are already waiting to trigger recents via alt-tab if (mFastAltTabTrigger.isDozing()) { @@ -375,7 +363,6 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements } } - @Override public void preloadRecents() { // Preload only the raw task list into a new load plan (which will be consumed by the // RecentsActivity) only if there is a task to animate to. @@ -396,17 +383,14 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements } } - @Override public void cancelPreloadingRecents() { // Do nothing } - @Override public void onDraggingInRecents(float distanceFromTop) { EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEvent(distanceFromTop)); } - @Override public void onDraggingInRecentsEnded(float velocity) { EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity)); } @@ -547,14 +531,18 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements showRelativeAffiliatedTask(false); } - public void dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) { + public boolean dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) { SystemServicesProxy ssp = Recents.getSystemServices(); ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); - if (topTask != null && !SystemServicesProxy.isHomeStack(topTask.stackId)) { + boolean screenPinningActive = ssp.isScreenPinningActive(); + boolean isTopTaskHome = SystemServicesProxy.isHomeStack(topTask.stackId); + if (topTask != null && !isTopTaskHome && !screenPinningActive) { ssp.moveTaskToDockedStack(topTask.id, stackCreateMode, initialBounds); showRecents(false /* triggeredFromAltTab */, draggingInRecents, false /* animate */, true /* reloadTasks*/); + return true; } + return false; } /** @@ -567,6 +555,26 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements } /** + * Reloads all the layouts for the header bar transition. + */ + private void reloadHeaderBarLayout() { + Resources res = mContext.getResources(); + LayoutInflater inflater = LayoutInflater.from(mContext); + + mStatusBarHeight = res.getDimensionPixelSize( + com.android.internal.R.dimen.status_bar_height); + mNavBarHeight = res.getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_height); + mNavBarWidth = res.getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_width); + mTaskBarHeight = res.getDimensionPixelSize( + R.dimen.recents_task_bar_height); + mDummyStackView = new TaskStackView(mContext, new TaskStack()); + mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header, + null, false); + } + + /** * Prepares the header bar layout for the next transition, if the task view bounds has changed * since the last call, it will attempt to re-measure and layout the header bar to the new size. * @@ -574,7 +582,8 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements * is not already bound (can be expensive) * @param stack the stack to initialize the stack layout with */ - private void reloadHeaderBarLayout(boolean tryAndBindSearchWidget, TaskStack stack) { + private void updateHeaderBarLayout(boolean tryAndBindSearchWidget, + TaskStack stack) { RecentsConfiguration config = Recents.getConfiguration(); SystemServicesProxy ssp = Recents.getSystemServices(); Rect windowRect = ssp.getWindowRect(); @@ -639,7 +648,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements preloadIcon(topTask); // Update the header bar if necessary - reloadHeaderBarLayout(false /* tryAndBindSearchWidget */, stack); + updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack); // Update the destination rect mDummyStackView.updateLayoutForStack(stack); @@ -825,7 +834,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements TaskStack stack = sInstanceLoadPlan.getTaskStack(); // Update the header bar if necessary - reloadHeaderBarLayout(false /* tryAndBindSearchWidget */, stack); + updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack); // Prepare the dummy stack for the transition mDummyStackView.updateLayoutForStack(stack); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index dfcf41bcebbf..3406da94e53c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -506,7 +506,7 @@ public class SystemServicesProxy { public void sendCloseSystemWindows(String reason) { if (ActivityManagerNative.isSystemReady()) { try { - ActivityManagerNative.getDefault().closeSystemDialogs(reason); + mIam.closeSystemDialogs(reason); } catch (RemoteException e) { } } @@ -779,6 +779,19 @@ public class SystemServicesProxy { } /** + * Returns whether the current task is in screen-pinning mode. + */ + public boolean isScreenPinningActive() { + if (mIam == null) return false; + + try { + return mIam.isInLockTaskMode(); + } catch (RemoteException e) { + return false; + } + } + + /** * Returns a global setting. */ public int getGlobalSetting(Context context, String setting) { 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 086fb5854fdb..2bf2ccba77c7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -88,15 +88,6 @@ public class Utilities { } /** - * Cancels an animation. - */ - public static void cancelAnimation(Animator animator) { - if (animator != null) { - animator.cancel(); - } - } - - /** * Cancels an animation ensuring that if it has listeners, onCancel and onEnd * are not called. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java index fce916b9d2d3..890713e5619d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java @@ -147,27 +147,11 @@ public class FreeformWorkspaceLayoutAlgorithm { public TaskViewTransform getTransform(Task task, TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) { if (mTaskRectMap.containsKey(task.key)) { - final Rect taskRect = stackLayout.mTaskRect; final RectF ffRect = mTaskRectMap.get(task.key); transformOut.scale = 1f; transformOut.alpha = 1f; transformOut.translationZ = stackLayout.mMaxTranslationZ; - if (task.thumbnail != null) { - if (task.bounds == null) { - // This is a stack task that has no freeform thumbnail, so keep the same bitmap - // scale as it had in the stack - transformOut.thumbnailScale = (float) taskRect.width() / - task.thumbnail.getWidth(); - } else { - // This is a freeform rect so fit the bitmap to the task bounds - transformOut.thumbnailScale = Math.min( - ffRect.width() / task.thumbnail.getWidth(), - ffRect.height() / task.thumbnail.getHeight()); - } - } else { - transformOut.thumbnailScale = 1f; - } transformOut.rect.set(ffRect); transformOut.rect.offset(stackLayout.mFreeformRect.left, stackLayout.mFreeformRect.top); transformOut.visible = true; 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 726e4537a620..c2bb74567599 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -592,12 +592,8 @@ public class TaskStackLayoutAlgorithm { transformOut.reset(); return transformOut; } - getStackTransform(mTaskIndexMap.get(task.key), stackScroll, transformOut, + return getStackTransform(mTaskIndexMap.get(task.key), stackScroll, transformOut, frontTransform); - if (task.thumbnail != null) { - transformOut.thumbnailScale = (float) mTaskRect.width() / task.thumbnail.getWidth(); - } - return transformOut; } } @@ -661,7 +657,6 @@ public class TaskStackLayoutAlgorithm { Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale); transformOut.visible = (transformOut.rect.top < mStackRect.bottom) && (frontTransform == null || transformOut.rect.top != frontTransform.rect.top); - transformOut.thumbnailScale = 1f; transformOut.p = relP; return transformOut; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index e8652f5b5d7b..bc441b26016c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -200,8 +200,15 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); - mHeaderView.onTaskViewSizeChanged(w, h); - mThumbnailView.onTaskViewSizeChanged(w, h); + if (w > 0 && h > 0) { + mHeaderView.onTaskViewSizeChanged(w, h); + mThumbnailView.onTaskViewSizeChanged(w, h); + } + } + + @Override + public boolean hasOverlappingRendering() { + return false; } @Override @@ -244,24 +251,17 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, TaskViewAnimation toAnimation, ValueAnimator.AnimatorUpdateListener updateCallback) { RecentsConfiguration config = Recents.getConfiguration(); - Utilities.cancelAnimation(mTransformAnimation); + Utilities.cancelAnimationWithoutCallbacks(mTransformAnimation); // Compose the animations for the transform mTmpAnimators.clear(); - boolean requiresHwLayers = toTransform.applyToTaskView(this, mTmpAnimators, toAnimation, - !config.fakeShadows); + toTransform.applyToTaskView(this, mTmpAnimators, toAnimation, !config.fakeShadows); if (toAnimation.isImmediate()) { - mThumbnailView.setBitmapScale(toTransform.thumbnailScale); setTaskProgress(toTransform.p); if (toAnimation.listener != null) { toAnimation.listener.onAnimationEnd(null); } } else { - if (Float.compare(mThumbnailView.getBitmapScale(), toTransform.thumbnailScale) != 0) { - mTmpAnimators.add(ObjectAnimator.ofFloat(mThumbnailView, - TaskViewThumbnail.BITMAP_SCALE, mThumbnailView.getBitmapScale(), - toTransform.thumbnailScale)); - } if (Float.compare(getTaskProgress(), toTransform.p) != 0) { mTmpAnimators.add(ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(), toTransform.p)); @@ -272,22 +272,13 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, // Create the animator mTransformAnimation = toAnimation.createAnimator(mTmpAnimators); - if (requiresHwLayers) { - setLayerType(View.LAYER_TYPE_HARDWARE, null); - mTransformAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - setLayerType(View.LAYER_TYPE_NONE, null); - } - }); - } mTransformAnimation.start(); } } /** Resets this view's properties */ void resetViewProperties() { - Utilities.cancelAnimation(mTransformAnimation); + Utilities.cancelAnimationWithoutCallbacks(mTransformAnimation); setDim(0); setVisibility(View.VISIBLE); getViewBounds().reset(); @@ -303,7 +294,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, * Cancels any current transform animations. */ public void cancelTransformAnimation() { - Utilities.cancelAnimation(mTransformAnimation); + Utilities.cancelAnimationWithoutCallbacks(mTransformAnimation); } /** Enables/disables handling touch on this task view. */ @@ -389,7 +380,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, } else { float dimAlpha = mDimAlpha / 255.0f; mThumbnailView.setDimAlpha(dimAlpha); - mHeaderView.setDimAlpha(dim); + mHeaderView.setDimAlpha(dimAlpha); } } 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 e8b7574b0ffb..6a474242903a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -16,18 +16,18 @@ package com.android.systemui.recents.views; +import android.annotation.Nullable; import android.content.Context; -import android.content.res.ColorStateList; +import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; +import android.graphics.PixelFormat; import android.graphics.Rect; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.RippleDrawable; +import android.support.v4.graphics.ColorUtils; import android.util.AttributeSet; import android.view.View; import android.view.animation.AnimationUtils; @@ -36,6 +36,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; + import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.Recents; @@ -55,6 +56,66 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; public class TaskViewHeader extends FrameLayout implements View.OnClickListener, View.OnLongClickListener { + private static final float HIGHLIGHT_LIGHTNESS_INCREMENT = 0.125f; + + /** + * A color drawable that draws a slight highlight at the top to help it stand out. + */ + private class HighlightColorDrawable extends Drawable { + + private Paint mHighlightPaint = new Paint(); + private Paint mBackgroundPaint = new Paint(); + + private float[] mTmpHSL = new float[3]; + + public HighlightColorDrawable() { + mBackgroundPaint.setColor(Color.argb(255, 0, 0, 0)); + mBackgroundPaint.setAntiAlias(true); + mHighlightPaint.setColor(Color.argb(255, 255, 255, 255)); + mHighlightPaint.setAntiAlias(true); + } + + public void setColorAndDim(int color, float dimAlpha) { + mBackgroundPaint.setColor(color); + + ColorUtils.colorToHSL(color, mTmpHSL); + // TODO: Consider using the saturation of the color to adjust the lightness as well + mTmpHSL[2] = Math.min(1f, + mTmpHSL[2] + HIGHLIGHT_LIGHTNESS_INCREMENT * (1.0f - dimAlpha)); + mHighlightPaint.setColor(ColorUtils.HSLToColor(mTmpHSL)); + + invalidateSelf(); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + // Do nothing + } + + @Override + public void setAlpha(int alpha) { + // Do nothing + } + + @Override + public void draw(Canvas canvas) { + // Draw the highlight at the top edge (but put the bottom edge just out of view) + canvas.drawRoundRect(0, 0, mTaskViewRect.width(), + 2 * Math.max(mHighlightHeight, mCornerRadius), + mCornerRadius, mCornerRadius, mHighlightPaint); + + // Draw the background with the rounded corners + canvas.drawRoundRect(0, mHighlightHeight, mTaskViewRect.width(), + getHeight() + mCornerRadius, + mCornerRadius, mCornerRadius, mBackgroundPaint); + } + + @Override + public int getOpacity() { + return PixelFormat.OPAQUE; + } + } + Task mTask; // Header views @@ -68,17 +129,18 @@ public class TaskViewHeader extends FrameLayout Rect mTaskViewRect = new Rect(); int mCornerRadius; int mHighlightHeight; + float mDimAlpha; Drawable mLightDismissDrawable; Drawable mDarkDismissDrawable; - RippleDrawable mBackground; - GradientDrawable mBackgroundColorDrawable; + int mTaskBarViewLightTextColor; + int mTaskBarViewDarkTextColor; String mDismissContentDescription; - // Static highlight that we draw at the top of each view - static Paint sHighlightPaint; + // Header background + private HighlightColorDrawable mBackground; // Header dim, which is only used when task view hardware layers are not used - Paint mDimLayerPaint = new Paint(); + private Paint mDimLayerPaint = new Paint(); Interpolator mFastOutSlowInInterpolator; Interpolator mFastOutLinearInInterpolator; @@ -100,29 +162,26 @@ public class TaskViewHeader extends FrameLayout setWillNotDraw(false); // Load the dismiss resources - mDimLayerPaint.setColor(Color.argb(0, 0, 0, 0)); + Resources res = context.getResources(); mLightDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_light); mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark); - mDismissContentDescription = - context.getString(R.string.accessibility_recents_item_will_be_dismissed); - mCornerRadius = getResources().getDimensionPixelSize( - R.dimen.recents_task_view_rounded_corners_radius); - mHighlightHeight = getResources().getDimensionPixelSize( - R.dimen.recents_task_view_highlight); + mDismissContentDescription = context.getString( + R.string.accessibility_recents_item_will_be_dismissed); + mCornerRadius = res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); + mHighlightHeight = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight); + mTaskBarViewLightTextColor = context.getColor(R.color.recents_task_bar_light_text_color); + mTaskBarViewDarkTextColor = context.getColor(R.color.recents_task_bar_dark_text_color); mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.fast_out_slow_in); mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.fast_out_linear_in); - // Configure the highlight paint - if (sHighlightPaint == null) { - sHighlightPaint = new Paint(); - sHighlightPaint.setStyle(Paint.Style.STROKE); - sHighlightPaint.setStrokeWidth(mHighlightHeight); - sHighlightPaint.setColor(context.getColor(R.color.recents_task_bar_highlight_color)); - sHighlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); - sHighlightPaint.setAntiAlias(true); - } + // Configure the background and dim + mBackground = new HighlightColorDrawable(); + mBackground.setColorAndDim(Color.argb(255, 0, 0, 0), 0f); + setBackground(mBackground); + mDimLayerPaint.setColor(Color.argb(255, 0, 0, 0)); + mDimLayerPaint.setAntiAlias(true); } @Override @@ -139,16 +198,6 @@ public class TaskViewHeader extends FrameLayout if (mIconView.getBackground() instanceof RippleDrawable) { mIconView.setBackground(null); } - - mBackgroundColorDrawable = (GradientDrawable) getContext().getDrawable( - R.drawable.recents_task_view_header_bg_color); - // Copy the ripple drawable since we are going to be manipulating it - mBackground = (RippleDrawable) - getContext().getDrawable(R.drawable.recents_task_view_header_bg); - mBackground = (RippleDrawable) mBackground.mutate().getConstantState().newDrawable(); - mBackground.setColor(ColorStateList.valueOf(0)); - mBackground.setDrawableByLayerId(mBackground.getId(0), mBackgroundColorDrawable); - setBackground(mBackground); } /** @@ -156,6 +205,11 @@ public class TaskViewHeader extends FrameLayout * to match the frame changes. */ public void onTaskViewSizeChanged(int width, int height) { + // Return early if the bounds have not changed + if (mTaskViewRect.width() == width && mTaskViewRect.height() == height) { + return; + } + mTaskViewRect.set(0, 0, width, height); boolean updateMoveTaskButton = mMoveTaskButton.getVisibility() != View.GONE; int appIconWidth = mIconView.getMeasuredWidth(); @@ -201,31 +255,39 @@ public class TaskViewHeader extends FrameLayout } @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - onTaskViewSizeChanged(mTaskViewRect.width(), mTaskViewRect.height()); + protected boolean verifyDrawable(Drawable who) { + return super.verifyDrawable(who) || (who == mBackground); } @Override - protected void onDraw(Canvas canvas) { - // Draw the highlight at the top edge (but put the bottom edge just out of view) - float offset = (float) Math.ceil(mHighlightHeight / 2f); - float radius = mCornerRadius; - int count = canvas.save(Canvas.CLIP_SAVE_FLAG); - canvas.clipRect(0, 0, mTaskViewRect.width(), getMeasuredHeight()); - canvas.drawRoundRect(-offset, 0f, (float) mTaskViewRect.width() + offset, - getMeasuredHeight() + radius, radius, radius, sHighlightPaint); - canvas.restoreToCount(count); + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + + // Draw the dim layer with the rounded corners + canvas.drawRoundRect(0, 0, mTaskViewRect.width(), getHeight() + mCornerRadius, + mCornerRadius, mCornerRadius, mDimLayerPaint); } /** * Sets the dim alpha, only used when we are not using hardware layers. * (see RecentsConfiguration.useHardwareLayers) */ - void setDimAlpha(int alpha) { - mDimLayerPaint.setColor(Color.argb(alpha, 0, 0, 0)); + void setDimAlpha(float dimAlpha) { + mDimAlpha = dimAlpha; + updateBackgroundColor(dimAlpha); invalidate(); } + /** + * Updates the background and highlight colors for this header. + */ + private void updateBackgroundColor(float dimAlpha) { + if (mTask != null) { + mBackground.setColorAndDim(mTask.colorPrimary, dimAlpha); + mDimLayerPaint.setAlpha((int) (dimAlpha * 255)); + } + } + /** Binds the bar view to the task */ public void rebindToTask(Task t) { SystemServicesProxy ssp = Recents.getSystemServices(); @@ -233,6 +295,7 @@ public class TaskViewHeader extends FrameLayout // If an activity icon is defined, then we use that as the primary icon to show in the bar, // otherwise, we fall back to the application icon + updateBackgroundColor(mDimAlpha); if (t.icon != null) { mIconView.setImageDrawable(t.icon); } @@ -240,20 +303,8 @@ public class TaskViewHeader extends FrameLayout mTitleView.setText(t.title); } mTitleView.setContentDescription(t.contentDescription); - - // Try and apply the system ui tint - int existingBgColor = (getBackground() instanceof ColorDrawable) ? - ((ColorDrawable) getBackground()).getColor() : 0; - if (existingBgColor != t.colorPrimary) { - mBackgroundColorDrawable.setColor(t.colorPrimary); - } - - int taskBarViewLightTextColor = getResources().getColor( - R.color.recents_task_bar_light_text_color); - int taskBarViewDarkTextColor = getResources().getColor( - R.color.recents_task_bar_dark_text_color); mTitleView.setTextColor(t.useLightOnPrimaryColor ? - taskBarViewLightTextColor : taskBarViewDarkTextColor); + mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor); mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ? mLightDismissDrawable : mDarkDismissDrawable); mDismissButton.setContentDescription(String.format(mDismissContentDescription, @@ -273,7 +324,9 @@ public class TaskViewHeader extends FrameLayout ? R.drawable.recents_move_task_freeform_light : R.drawable.recents_move_task_freeform_dark); } - mMoveTaskButton.setVisibility(View.VISIBLE); + if (mMoveTaskButton.getVisibility() != View.VISIBLE) { + mMoveTaskButton.setVisibility(View.VISIBLE); + } mMoveTaskButton.setOnClickListener(this); } @@ -329,15 +382,6 @@ public class TaskViewHeader extends FrameLayout } @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - - // Draw the dim layer with the rounded corners - canvas.drawRoundRect(0, 0, mTaskViewRect.width(), getHeight(), - mCornerRadius, mCornerRadius, mDimLayerPaint); - } - - @Override public void onClick(View v) { if (v == mIconView) { // In accessibility, a single click on the focused app info button will show it 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 8edfae052fcc..39d06049edaf 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -42,26 +42,15 @@ import com.android.systemui.recents.model.Task; */ public class TaskViewThumbnail extends View { - public static final Property<TaskViewThumbnail, Float> BITMAP_SCALE = - new FloatProperty<TaskViewThumbnail>("bitmapScale") { - @Override - public void setValue(TaskViewThumbnail object, float scale) { - object.setBitmapScale(scale); - } - - @Override - public Float get(TaskViewThumbnail object) { - return object.getBitmapScale(); - } - }; + private Task mTask; // Drawing + Rect mThumbnailRect = new Rect(); Rect mTaskViewRect = new Rect(); int mCornerRadius; float mDimAlpha; Matrix mScaleMatrix = new Matrix(); Paint mDrawPaint = new Paint(); - float mBitmapScale = 1f; BitmapShader mBitmapShader; LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0); @@ -104,7 +93,13 @@ public class TaskViewThumbnail extends View { * to match the frame changes. */ public void onTaskViewSizeChanged(int width, int height) { + // Return early if the bounds have not changed + if (mTaskViewRect.width() == width && mTaskViewRect.height() == height) { + return; + } + mTaskViewRect.set(0, 0, width, height); + updateThumbnailScale(); invalidate(); } @@ -125,9 +120,12 @@ public class TaskViewThumbnail extends View { mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mDrawPaint.setShader(mBitmapShader); + mThumbnailRect.set(0, 0, bm.getWidth(), bm.getHeight()); + updateThumbnailScale(); } else { mBitmapShader = null; mDrawPaint.setShader(null); + mThumbnailRect.setEmpty(); } invalidate(); } @@ -151,12 +149,23 @@ public class TaskViewThumbnail extends View { } /** - * Sets the scale of the bitmap relative to this view. + * Updates the scale of the bitmap relative to this view. */ - public void setBitmapScale(float scale) { + public void updateThumbnailScale() { if (mBitmapShader != null) { - mBitmapScale = scale; - mScaleMatrix.setScale(mBitmapScale, mBitmapScale); + float thumbnailScale; + if (!mTask.isFreeformTask() || mTask.bounds == null) { + // If this is a stack task, or a stack task moved into the freeform workspace, then + // just scale this thumbnail to fit the width of the view + thumbnailScale = (float) mTaskViewRect.width() / mThumbnailRect.width(); + } else { + // Otherwise, if this is a freeform task with task bounds, then scale the thumbnail + // to fit the entire bitmap into the task bounds + thumbnailScale = Math.min( + (float) mTaskViewRect.width() / mThumbnailRect.width(), + (float) mTaskViewRect.height() / mThumbnailRect.height()); + } + mScaleMatrix.setScale(thumbnailScale, thumbnailScale); mBitmapShader.setLocalMatrix(mScaleMatrix); } if (!mInvisible) { @@ -164,10 +173,6 @@ public class TaskViewThumbnail extends View { } } - public float getBitmapScale() { - return mBitmapScale; - } - /** Updates the clip rect based on the given task bar. */ void updateClipToTaskBar(View taskBar) { mTaskBar = taskBar; @@ -200,6 +205,7 @@ public class TaskViewThumbnail extends View { /** Binds the thumbnail view to the task */ void rebindToTask(Task t) { + mTask = t; if (t.thumbnail != null) { setThumbnail(t.thumbnail); } else { @@ -209,6 +215,7 @@ public class TaskViewThumbnail extends View { /** Unbinds the thumbnail view from the task */ void unbindFromTask() { + mTask = null; setThumbnail(null); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java index 14bab6462da3..538c2483cb9f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java @@ -86,7 +86,6 @@ public class TaskViewTransform { public float translationZ = 0; public float scale = 1f; public float alpha = 1f; - public float thumbnailScale = 1f; public boolean visible = false; float p = 0f; @@ -101,7 +100,6 @@ public class TaskViewTransform { translationZ = 0; scale = 1f; alpha = 1f; - thumbnailScale = 1f; visible = false; rect.setEmpty(); p = 0f; @@ -127,15 +125,12 @@ public class TaskViewTransform { /** * Applies this transform to a view. - * - * @return whether hardware layers are required for this animation. */ - public boolean applyToTaskView(TaskView v, ArrayList<Animator> animators, + public void applyToTaskView(TaskView v, ArrayList<Animator> animators, TaskViewAnimation taskAnimation, boolean allowShadows) { // Return early if not visible - boolean requiresHwLayers = false; if (!visible) { - return requiresHwLayers; + return; } if (taskAnimation.isImmediate()) { @@ -165,7 +160,6 @@ public class TaskViewTransform { } if (hasAlphaChangedFrom(v.getAlpha())) { animators.add(ObjectAnimator.ofFloat(v, View.ALPHA, v.getAlpha(), alpha)); - requiresHwLayers = true; } if (hasRectChangedFrom(v)) { animators.add(ObjectAnimator.ofPropertyValuesHolder(v, @@ -175,7 +169,6 @@ public class TaskViewTransform { PropertyValuesHolder.ofInt(BOTTOM, v.getBottom(), (int) rect.bottom))); } } - return requiresHwLayers; } /** Reset the transform on a view. */ @@ -188,6 +181,5 @@ public class TaskViewTransform { v.setAlpha(1f); v.getViewBounds().setClipBottom(0); v.setLeftTopRightBottom(0, 0, 0, 0); - v.mThumbnailView.setBitmapScale(1f); } } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 109cf4726101..824d10a3aa19 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -28,7 +28,6 @@ import android.graphics.Rect; import android.graphics.Region.Op; import android.hardware.display.DisplayManager; import android.util.AttributeSet; -import android.util.MathUtils; import android.view.Display; import android.view.DisplayInfo; import android.view.MotionEvent; @@ -39,7 +38,6 @@ import android.view.View.OnTouchListener; import android.view.ViewConfiguration; import android.view.ViewTreeObserver.InternalInsetsInfo; import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; -import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.AnimationUtils; @@ -48,8 +46,10 @@ import android.view.animation.PathInterpolator; import android.widget.FrameLayout; import android.widget.ImageButton; +import com.android.internal.policy.DividerSnapAlgorithm; +import com.android.internal.policy.DockedDividerUtils; import com.android.systemui.R; -import com.android.systemui.stackdivider.DividerSnapAlgorithm.SnapTarget; +import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.systemui.statusbar.FlingAnimationUtils; import static android.view.PointerIcon.STYLE_HORIZONTAL_DOUBLE_ARROW; @@ -167,7 +167,8 @@ public class DividerView extends FrameLayout implements OnTouchListener, public boolean startDragging(boolean animate) { mHandle.setTouching(true, animate); mDockSide = mWindowManagerProxy.getDockSide(); - mSnapAlgorithm = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils, mDisplayWidth, + mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), + mFlingAnimationUtils.getMinVelocityPxPerSecond(), mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets); if (mDockSide != WindowManager.DOCKED_INVALID) { mWindowManagerProxy.setResizing(true); @@ -362,36 +363,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, return mStartPosition + touchY - mStartY; } - public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) { - outRect.set(0, 0, mDisplayWidth, mDisplayHeight); - switch (dockSide) { - case WindowManager.DOCKED_LEFT: - outRect.right = position; - break; - case WindowManager.DOCKED_TOP: - outRect.bottom = position; - break; - case WindowManager.DOCKED_RIGHT: - outRect.left = position + mDividerWindowWidth - 2 * mDividerInsets; - break; - case WindowManager.DOCKED_BOTTOM: - outRect.top = position + mDividerWindowWidth - 2 * mDividerInsets; - break; - } - if (outRect.left > outRect.right) { - outRect.left = outRect.right; - } - if (outRect.top > outRect.bottom) { - outRect.top = outRect.bottom; - } - if (outRect.right < outRect.left) { - outRect.right = outRect.left; - } - if (outRect.bottom < outRect.top) { - outRect.bottom = outRect.top; - } - } - private int invertDockSide(int dockSide) { switch (dockSide) { case WindowManager.DOCKED_LEFT: @@ -421,6 +392,11 @@ public class DividerView extends FrameLayout implements OnTouchListener, containingRect.right, containingRect.bottom); } + public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) { + DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect, mDisplayWidth, + mDisplayHeight, mDividerSize); + } + public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) { calculateBoundsForPosition(position, mDockSide, mDockedRect); 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 b93fc760ce2c..f41e47bf9e0e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -166,7 +166,7 @@ public class KeyguardStatusBarView extends RelativeLayout } @Override - public void onPowerSaveChanged() { + public void onPowerSaveChanged(boolean isPowerSave) { // could not care less } 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 cc85d0fb8a25..e5b4f4d0369d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -29,8 +29,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.stackdivider.Divider; -import com.android.systemui.stackdivider.DividerSnapAlgorithm.SnapTarget; -import com.android.systemui.stackdivider.DividerView; +import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.systemui.tuner.TunerService; import static android.view.WindowManager.*; @@ -166,16 +165,19 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL int y = (int) event.getY(); int xDiff = Math.abs(x - mTouchDownX); int yDiff = Math.abs(y - mTouchDownY); + if (mDivider == null || mRecentsComponent == null) { + return false; + } if (!mDockWindowTouchSlopExceeded) { boolean touchSlopExceeded = !mIsVertical ? yDiff > mScrollTouchSlop && yDiff > xDiff : xDiff > mScrollTouchSlop && xDiff > yDiff; if (touchSlopExceeded && mDivider.getView().getWindowManagerProxy().getDockSide() == DOCKED_INVALID) { - mDragMode = calculateDragMode(); Rect initialBounds = null; + int dragMode = calculateDragMode(); int createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; - if (mDragMode == DRAG_MODE_DIVIDER) { + if (dragMode == DRAG_MODE_DIVIDER) { initialBounds = new Rect(); mDivider.getView().calculateBoundsForPosition(mIsVertical ? (int) event.getRawX() @@ -184,19 +186,23 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL ? DOCKED_TOP : DOCKED_LEFT, initialBounds); - } else if (mDragMode == DRAG_MODE_RECENTS && mTouchDownX + } else if (dragMode == DRAG_MODE_RECENTS && mTouchDownX < mContext.getResources().getDisplayMetrics().widthPixels / 2) { createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; } - mRecentsComponent.dockTopTask(mDragMode == DRAG_MODE_RECENTS, createMode, - initialBounds); - if (mDragMode == DRAG_MODE_DIVIDER) { - mDivider.getView().startDragging(false /* animate */); + boolean docked = mRecentsComponent.dockTopTask(dragMode == DRAG_MODE_RECENTS, + createMode, initialBounds); + if (docked) { + mDragMode = dragMode; + if (mDragMode == DRAG_MODE_DIVIDER) { + mDivider.getView().startDragging(false /* animate */); + } + mDockWindowTouchSlopExceeded = true; + MetricsLogger.action(mContext, + MetricsLogger.ACTION_WINDOW_DOCK_SWIPE); + + return true; } - mDockWindowTouchSlopExceeded = true; - MetricsLogger.action(mContext, - MetricsLogger.ACTION_WINDOW_DOCK_SWIPE); - return true; } } else { if (mDragMode == DRAG_MODE_DIVIDER) { @@ -214,7 +220,7 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL private void handleDragActionUpEvent(MotionEvent event) { mVelocityTracker.addMovement(event); mVelocityTracker.computeCurrentVelocity(1000); - if (mDockWindowTouchSlopExceeded) { + if (mDockWindowTouchSlopExceeded && mDivider != null && mRecentsComponent != null) { if (mDragMode == DRAG_MODE_DIVIDER) { mDivider.getView().stopDragging(mIsVertical ? (int) event.getRawX() @@ -254,7 +260,7 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL float absVelY = Math.abs(velocityY); boolean isValidFling = absVelX > mMinFlingVelocity && mIsVertical ? (absVelY > absVelX) : (absVelX > absVelY); - if (isValidFling) { + if (isValidFling && mRecentsComponent != null) { boolean showNext; if (!mIsRTL) { showNext = mIsVertical ? (velocityY < 0) : (velocityX < 0); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index 6aa072ff2c81..f2c57e538829 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -23,8 +23,6 @@ import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; -import java.util.ArrayList; - public abstract class PanelBar extends FrameLayout { public static final boolean DEBUG = false; public static final String TAG = PanelBar.class.getSimpleName(); @@ -39,14 +37,10 @@ public abstract class PanelBar extends FrameLayout { public static final int STATE_OPENING = 1; public static final int STATE_OPEN = 2; - PanelHolder mPanelHolder; - ArrayList<PanelView> mPanels = new ArrayList<PanelView>(); - PanelView mTouchingPanel; + PanelView mPanel; private int mState = STATE_CLOSED; private boolean mTracking; - float mPanelExpandedFractionSum; - public void go(int state) { if (DEBUG) LOG("go state: %d -> %d", mState, state); mState = state; @@ -61,54 +55,28 @@ public abstract class PanelBar extends FrameLayout { super.onFinishInflate(); } - public void addPanel(PanelView pv) { - mPanels.add(pv); + public void setPanel(PanelView pv) { + mPanel = pv; pv.setBar(this); } - public void setPanelHolder(PanelHolder ph) { - if (ph == null) { - Log.e(TAG, "setPanelHolder: null PanelHolder", new Throwable()); - return; - } - mPanelHolder = ph; - final int N = ph.getChildCount(); - for (int i=0; i<N; i++) { - final View v = ph.getChildAt(i); - if (v != null && v instanceof PanelView) { - addPanel((PanelView) v); - } - } - } - public void setBouncerShowing(boolean showing) { int important = showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS : IMPORTANT_FOR_ACCESSIBILITY_AUTO; setImportantForAccessibility(important); - if (mPanelHolder != null) { - mPanelHolder.setImportantForAccessibility(important); - } + if (mPanel != null) mPanel.setImportantForAccessibility(important); } - public float getBarHeight() { - return getMeasuredHeight(); - } - - public PanelView selectPanelForTouch(MotionEvent touch) { - final int N = mPanels.size(); - return mPanels.get((int)(N * touch.getX() / getMeasuredWidth())); - } - - public boolean panelsEnabled() { + public boolean panelEnabled() { return true; } @Override public boolean onTouchEvent(MotionEvent event) { // Allow subclasses to implement enable/disable semantics - if (!panelsEnabled()) { + if (!panelEnabled()) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Log.v(TAG, String.format("onTouch: all panels disabled, ignoring touch at (%d,%d)", (int) event.getX(), (int) event.getY())); @@ -116,14 +84,12 @@ public abstract class PanelBar extends FrameLayout { return false; } - // figure out which panel needs to be talked to here if (event.getAction() == MotionEvent.ACTION_DOWN) { - final PanelView panel = selectPanelForTouch(event); + final PanelView panel = mPanel; if (panel == null) { // panel is not there, so we'll eat the gesture Log.v(TAG, String.format("onTouch: no panel for touch at (%d,%d)", (int) event.getX(), (int) event.getY())); - mTouchingPanel = null; return true; } boolean enabled = panel.isEnabled(); @@ -134,90 +100,65 @@ public abstract class PanelBar extends FrameLayout { Log.v(TAG, String.format( "onTouch: panel (%s) is disabled, ignoring touch at (%d,%d)", panel, (int) event.getX(), (int) event.getY())); - mTouchingPanel = null; return true; } - startOpeningPanel(panel); - } - final boolean result = mTouchingPanel != null - ? mTouchingPanel.onTouchEvent(event) - : true; - return result; - } - - // called from PanelView when self-expanding, too - public void startOpeningPanel(PanelView panel) { - if (DEBUG) LOG("startOpeningPanel: " + panel); - mTouchingPanel = panel; - mPanelHolder.setSelectedPanel(mTouchingPanel); - for (PanelView pv : mPanels) { - if (pv != panel) { - pv.collapse(false /* delayed */, 1.0f /* speedUpFactor */); - } } + return mPanel == null || mPanel.onTouchEvent(event); } public abstract void panelScrimMinFractionChanged(float minFraction); /** - * @param panel the panel which changed its expansion state * @param frac the fraction from the expansion in [0, 1] * @param expanded whether the panel is currently expanded; this is independent from the * fraction as the panel also might be expanded if the fraction is 0 */ - public void panelExpansionChanged(PanelView panel, float frac, boolean expanded) { + public void panelExpansionChanged(float frac, boolean expanded) { boolean fullyClosed = true; - PanelView fullyOpenedPanel = null; - if (SPEW) LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName()); - mPanelExpandedFractionSum = 0f; - for (PanelView pv : mPanels) { - pv.setVisibility(expanded ? View.VISIBLE : View.INVISIBLE); - // adjust any other panels that may be partially visible - if (expanded) { - if (mState == STATE_CLOSED) { - go(STATE_OPENING); - onPanelPeeked(); - } - fullyClosed = false; - final float thisFrac = pv.getExpandedFraction(); - mPanelExpandedFractionSum += thisFrac; - if (SPEW) LOG("panelExpansionChanged: -> %s: f=%.1f", pv.getName(), thisFrac); - if (panel == pv) { - if (thisFrac == 1f) fullyOpenedPanel = panel; - } + boolean fullyOpened = false; + if (SPEW) LOG("panelExpansionChanged: start state=%d", mState); + PanelView pv = mPanel; + pv.setVisibility(expanded ? View.VISIBLE : View.INVISIBLE); + // adjust any other panels that may be partially visible + if (expanded) { + if (mState == STATE_CLOSED) { + go(STATE_OPENING); + onPanelPeeked(); } + fullyClosed = false; + final float thisFrac = pv.getExpandedFraction(); + if (SPEW) LOG("panelExpansionChanged: -> %s: f=%.1f", pv.getName(), thisFrac); + fullyOpened = thisFrac >= 1f; } - mPanelExpandedFractionSum /= mPanels.size(); - if (fullyOpenedPanel != null && !mTracking) { + if (fullyOpened && !mTracking) { go(STATE_OPEN); - onPanelFullyOpened(fullyOpenedPanel); + onPanelFullyOpened(); } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) { go(STATE_CLOSED); - onAllPanelsCollapsed(); + onPanelCollapsed(); } if (SPEW) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState, - (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":""); + fullyOpened?" fullyOpened":"", fullyClosed?" fullyClosed":""); } - public void collapseAllPanels(boolean animate, boolean delayed, float speedUpFactor) { + public void collapsePanel(boolean animate, boolean delayed, float speedUpFactor) { boolean waiting = false; - for (PanelView pv : mPanels) { - if (animate && !pv.isFullyCollapsed()) { - pv.collapse(delayed, speedUpFactor); - waiting = true; - } else { - pv.resetViews(); - pv.setExpandedFraction(0); // just in case - pv.cancelPeek(); - } + PanelView pv = mPanel; + if (animate && !pv.isFullyCollapsed()) { + pv.collapse(delayed, speedUpFactor); + waiting = true; + } else { + pv.resetViews(); + pv.setExpandedFraction(0); // just in case + pv.cancelPeek(); } - if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting); + if (DEBUG) LOG("collapsePanel: animate=%s waiting=%s", animate, waiting); if (!waiting && mState != STATE_CLOSED) { // it's possible that nothing animated, so we replicate the termination // conditions of panelExpansionChanged here go(STATE_CLOSED); - onAllPanelsCollapsed(); + onPanelCollapsed(); } } @@ -225,19 +166,19 @@ public abstract class PanelBar extends FrameLayout { if (DEBUG) LOG("onPanelPeeked"); } - public void onAllPanelsCollapsed() { - if (DEBUG) LOG("onAllPanelsCollapsed"); + public void onPanelCollapsed() { + if (DEBUG) LOG("onPanelCollapsed"); } - public void onPanelFullyOpened(PanelView openPanel) { + public void onPanelFullyOpened() { if (DEBUG) LOG("onPanelFullyOpened"); } - public void onTrackingStarted(PanelView panel) { + public void onTrackingStarted() { mTracking = true; } - public void onTrackingStopped(PanelView panel, boolean expand) { + public void onTrackingStopped(boolean expand) { mTracking = false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java deleted file mode 100644 index 5095ebb95ec1..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.EventLog; -import android.view.MotionEvent; -import android.widget.FrameLayout; - -import com.android.systemui.EventLogTags; - -public class PanelHolder extends FrameLayout { - public static final boolean DEBUG_GESTURES = true; - - private int mSelectedPanelIndex = -1; - - public PanelHolder(Context context, AttributeSet attrs) { - super(context, attrs); - setChildrenDrawingOrderEnabled(true); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - setChildrenDrawingOrderEnabled(true); - } - - public int getPanelIndex(PanelView pv) { - final int N = getChildCount(); - for (int i=0; i<N; i++) { - final PanelView v = (PanelView) getChildAt(i); - if (pv == v) return i; - } - return -1; - } - - public void setSelectedPanel(PanelView pv) { - mSelectedPanelIndex = getPanelIndex(pv); - } - - @Override - protected int getChildDrawingOrder(int childCount, int i) { - if (mSelectedPanelIndex == -1) { - return i; - } else { - if (i == childCount - 1) { - return mSelectedPanelIndex; - } else if (i >= mSelectedPanelIndex) { - return i + 1; - } else { - return i; - } - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (DEBUG_GESTURES) { - if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { - EventLog.writeEvent(EventLogTags.SYSUI_PANELHOLDER_TOUCH, - event.getActionMasked(), (int) event.getX(), (int) event.getY()); - } - } - return false; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 7b2498f2ac72..aa01bf248853 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -432,7 +432,7 @@ public abstract class PanelView extends FrameLayout { protected void onTrackingStopped(boolean expand) { mTracking = false; - mBar.onTrackingStopped(PanelView.this, expand); + mBar.onTrackingStopped(expand); notifyBarPanelExpansionChanged(); } @@ -440,7 +440,7 @@ public abstract class PanelView extends FrameLayout { endClosing(); mTracking = true; mCollapseAfterPeek = false; - mBar.onTrackingStarted(PanelView.this); + mBar.onTrackingStarted(); notifyExpandingStarted(); notifyBarPanelExpansionChanged(); } @@ -893,7 +893,6 @@ public abstract class PanelView extends FrameLayout { != mStatusBar.getStatusBarHeight()) { getViewTreeObserver().removeOnGlobalLayoutListener(this); if (animate) { - mBar.startOpeningPanel(PanelView.this); notifyExpandingStarted(); fling(0, true /* expand */); } else { @@ -1025,7 +1024,7 @@ public abstract class PanelView extends FrameLayout { } protected void notifyBarPanelExpansionChanged() { - mBar.panelExpansionChanged(this, mExpandedFraction, mExpandedFraction > 0f || mPeekPending + mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f || mPeekPending || mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp() || mTracking || mHeightAnimator != null); } 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 d721a77b4055..50e88d39f1f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -81,7 +81,6 @@ import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.ThreadedRenderer; -import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.ViewStub; @@ -342,7 +341,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // Tracking finger for opening/closing. boolean mTracking; - VelocityTracker mVelocityTracker; int[] mAbsPos = new int[2]; ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); @@ -692,16 +690,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } }); - mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar); - mStatusBarView.setBar(this); - - PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder); - mStatusBarView.setPanelHolder(holder); - mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById( R.id.notification_panel); mNotificationPanel.setStatusBar(this); + mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar); + mStatusBarView.setBar(this); + mStatusBarView.setPanel(mNotificationPanel); + if (!ActivityManager.isHighEndGfx()) { mStatusBarWindow.setBackground(null); mNotificationPanel.setBackground(new FastColorDrawable(context.getColor( @@ -814,10 +810,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mBatteryController = new BatteryController(mContext); mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() { @Override - public void onPowerSaveChanged() { + public void onPowerSaveChanged(boolean isPowerSave) { mHandler.post(mCheckBarModes); if (mDozeServiceHost != null) { - mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave()); + mDozeServiceHost.firePowerSaveChanged(isPowerSave); } } @Override @@ -1128,12 +1124,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override public boolean onLongClick(View v) { if (mRecents != null) { - mRecents.dockTopTask(false /* draggingInRecents */, + boolean docked = mRecents.dockTopTask(false /* draggingInRecents */, ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */); - MetricsLogger.action(mContext, - MetricsLogger.ACTION_WINDOW_DOCK_LONGPRESS); - return true; + if (docked) { + MetricsLogger.action(mContext, + MetricsLogger.ACTION_WINDOW_DOCK_LONGPRESS); + return true; + } } return false; } @@ -2275,7 +2273,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mStatusBarWindowManager.setStatusBarFocusable(false); mStatusBarWindow.cancelExpandHelper(); - mStatusBarView.collapseAllPanels(true /* animate */, delayed, speedUpFactor); + mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor); } } @@ -2324,7 +2322,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void animateCollapseQuickSettings() { if (mState == StatusBarState.SHADE) { - mStatusBarView.collapseAllPanels(true, false /* delayed */, 1.0f /* speedUpFactor */); + mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */); } } @@ -2337,7 +2335,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) - mStatusBarView.collapseAllPanels(/*animate=*/ false, false /* delayed*/, + mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/, 1.0f /* speedUpFactor */); mNotificationPanel.closeQs(); @@ -2429,7 +2427,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mStatusBarWindowState = state; if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state)); if (!showing && mState == StatusBarState.SHADE) { - mStatusBarView.collapseAllPanels(false /* animate */, false /* delayed */, + mStatusBarView.collapsePanel(false /* animate */, false /* delayed */, 1.0f /* speedUpFactor */); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index ab37e6abc32b..813a1679290c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.phone; import android.content.Context; -import android.content.res.Resources; import android.util.AttributeSet; import android.util.EventLog; import android.view.MotionEvent; @@ -26,7 +25,6 @@ import android.view.accessibility.AccessibilityEvent; import com.android.systemui.DejankUtils; import com.android.systemui.EventLogTags; -import com.android.systemui.R; public class PhoneStatusBarView extends PanelBar { private static final String TAG = "PhoneStatusBarView"; @@ -35,8 +33,7 @@ public class PhoneStatusBarView extends PanelBar { PhoneStatusBar mBar; - PanelView mLastFullyOpenedPanel = null; - PanelView mNotificationPanel; + boolean mIsFullyOpenedPanel = false; private final PhoneStatusBarTransitions mBarTransitions; private ScrimController mScrimController; private float mMinFraction; @@ -72,15 +69,7 @@ public class PhoneStatusBarView extends PanelBar { } @Override - public void addPanel(PanelView pv) { - super.addPanel(pv); - if (pv.getId() == R.id.notification_panel) { - mNotificationPanel = pv; - } - } - - @Override - public boolean panelsEnabled() { + public boolean panelEnabled() { return mBar.panelsEnabled(); } @@ -100,24 +89,17 @@ public class PhoneStatusBarView extends PanelBar { } @Override - public PanelView selectPanelForTouch(MotionEvent touch) { - return mNotificationPanel.getExpandedHeight() > 0 - ? null - : mNotificationPanel; - } - - @Override public void onPanelPeeked() { super.onPanelPeeked(); mBar.makeExpandedVisible(false); } @Override - public void onAllPanelsCollapsed() { - super.onAllPanelsCollapsed(); + public void onPanelCollapsed() { + super.onPanelCollapsed(); // Close the status bar in the next frame so we can show the end of the animation. DejankUtils.postAfterTraversal(mHideExpandedRunnable); - mLastFullyOpenedPanel = null; + mIsFullyOpenedPanel = false; } public void removePendingHideExpandedRunnables() { @@ -125,12 +107,12 @@ public class PhoneStatusBarView extends PanelBar { } @Override - public void onPanelFullyOpened(PanelView openPanel) { - super.onPanelFullyOpened(openPanel); - if (openPanel != mLastFullyOpenedPanel) { - openPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + public void onPanelFullyOpened() { + super.onPanelFullyOpened(); + if (!mIsFullyOpenedPanel) { + mPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } - mLastFullyOpenedPanel = openPanel; + mIsFullyOpenedPanel = true; } @Override @@ -149,8 +131,8 @@ public class PhoneStatusBarView extends PanelBar { } @Override - public void onTrackingStarted(PanelView panel) { - super.onTrackingStarted(panel); + public void onTrackingStarted() { + super.onTrackingStarted(); mBar.onTrackingStarted(); mScrimController.onTrackingStarted(); } @@ -162,8 +144,8 @@ public class PhoneStatusBarView extends PanelBar { } @Override - public void onTrackingStopped(PanelView panel, boolean expand) { - super.onTrackingStopped(panel, expand); + public void onTrackingStopped(boolean expand) { + super.onTrackingStopped(expand); mBar.onTrackingStopped(expand); } @@ -187,8 +169,8 @@ public class PhoneStatusBarView extends PanelBar { } @Override - public void panelExpansionChanged(PanelView panel, float frac, boolean expanded) { - super.panelExpansionChanged(panel, frac, expanded); + public void panelExpansionChanged(float frac, boolean expanded) { + super.panelExpansionChanged(frac, expanded); mPanelFraction = frac; updateScrimFraction(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 3d21f44e4e24..d2f1ca9630e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -419,7 +419,7 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC } @Override - public void onPowerSaveChanged() { + public void onPowerSaveChanged(boolean isPowerSave) { // could not care less } 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 5071df0dee48..bb3e1166f2aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -70,9 +70,14 @@ public class BatteryController extends BroadcastReceiver { pw.print(" mPowerSave="); pw.println(mPowerSave); } + public void setPowerSaveMode(boolean powerSave) { + mPowerManager.setPowerSaveMode(powerSave); + } + public void addStateChangedCallback(BatteryStateChangeCallback cb) { mChangeCallbacks.add(cb); cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); + cb.onPowerSaveChanged(mPowerSave); } public void removeStateChangedCallback(BatteryStateChangeCallback cb) { @@ -158,12 +163,12 @@ public class BatteryController extends BroadcastReceiver { private void firePowerSaveChanged() { final int N = mChangeCallbacks.size(); for (int i = 0; i < N; i++) { - mChangeCallbacks.get(i).onPowerSaveChanged(); + mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave); } } public interface BatteryStateChangeCallback { void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging); - void onPowerSaveChanged(); + void onPowerSaveChanged(boolean isPowerSave); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index 03409846ed40..4ae0321ff68b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -35,25 +35,25 @@ public class BrightnessMirrorController { private final ScrimView mScrimBehind; private final View mBrightnessMirror; - private final View mPanelHolder; + private final View mNotificationPanel; private final int[] mInt2Cache = new int[2]; public BrightnessMirrorController(StatusBarWindowView statusBarWindow) { mScrimBehind = (ScrimView) statusBarWindow.findViewById(R.id.scrim_behind); mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror); - mPanelHolder = statusBarWindow.findViewById(R.id.panel_holder); + mNotificationPanel = statusBarWindow.findViewById(R.id.notification_panel); } public void showMirror() { mBrightnessMirror.setVisibility(View.VISIBLE); mScrimBehind.animateViewAlpha(0.0f, TRANSITION_DURATION_OUT, PhoneStatusBar.ALPHA_OUT); - outAnimation(mPanelHolder.animate()) + outAnimation(mNotificationPanel.animate()) .withLayer(); } public void hideMirror() { mScrimBehind.animateViewAlpha(1.0f, TRANSITION_DURATION_IN, PhoneStatusBar.ALPHA_IN); - inAnimation(mPanelHolder.animate()) + inAnimation(mNotificationPanel.animate()) .withLayer() .withEndAction(new Runnable() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index b010761aecc7..f3a355445ccf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -643,8 +643,8 @@ public class UserSwitcherController { private final Intent USER_SETTINGS_INTENT = new Intent("android.settings.USER_SETTINGS"); @Override - public int getTitle() { - return R.string.quick_settings_user_title; + public CharSequence getTitle() { + return mContext.getString(R.string.quick_settings_user_title); } @Override diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 5f6cbf9f0025..232c080266c0 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -69,6 +69,13 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo */ static final int FLAG_FEATURE_AUTOCLICK = 0x00000008; + /** + * Flag for enabling motion event injectsion + * + * @see #setUserAndEnabledFeatures(int, int) + */ + static final int FLAG_FEATURE_INJECT_MOTION_EVENTS = 0x00000010; + private final Runnable mProcessBatchedEventsRunnable = new Runnable() { @Override public void run() { @@ -104,6 +111,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo private MagnificationGestureHandler mMagnificationGestureHandler; + private MotionEventInjector mMotionEventInjector; + private AutoclickController mAutoclickController; private KeyboardInterceptor mKeyboardInterceptor; @@ -191,6 +200,10 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo } } + public MotionEventInjector getMotionEventInjector() { + return mMotionEventInjector; + } + /** * Gets current event stream state associated with an input event. * @return The event stream state that should be used for the event. Null if the event should @@ -351,6 +364,12 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo private void enableFeatures() { resetStreamState(); + if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) { + mMotionEventInjector = new MotionEventInjector(mContext.getMainLooper()); + addFirstEventHandler(mMotionEventInjector); + mAms.setMotionEventInjector(mMotionEventInjector); + } + if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) { mAutoclickController = new AutoclickController(mContext, mUserId); addFirstEventHandler(mAutoclickController); @@ -388,6 +407,11 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo } private void disableFeatures() { + if (mMotionEventInjector != null) { + mAms.setMotionEventInjector(null); + mMotionEventInjector.onDestroy(); + mMotionEventInjector = null; + } if (mAutoclickController != null) { mAutoclickController.onDestroy(); mAutoclickController = null; diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 8cf25b3bbd99..39d59525b522 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -37,6 +37,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; @@ -72,6 +73,7 @@ import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MagnificationSpec; +import android.view.MotionEvent; import android.view.WindowInfo; import android.view.WindowManager; import android.view.WindowManagerInternal; @@ -186,6 +188,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private KeyEventDispatcher mKeyEventDispatcher; + private MotionEventInjector mMotionEventInjector; + private final Set<ComponentName> mTempComponentNameSet = new HashSet<>(); private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList = @@ -779,6 +783,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } /** + * Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector. + * Not using a getter because the AccessibilityInputFilter isn't thread-safe + * + * @param motionEventInjector The new value of the motionEventInjector. May be null. + */ + void setMotionEventInjector(MotionEventInjector motionEventInjector) { + synchronized (mLock) { + mMotionEventInjector = motionEventInjector; + } + } + + /** * Gets a point within the accessibility focused node where we can send down * and up events to perform a click. * @@ -1273,6 +1289,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (userState.mIsAutoclickEnabled) { flags |= AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK; } + if (userState.mIsPerformGesturesEnabled) { + flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS; + } if (flags != 0) { if (!mHasInputFilter) { mHasInputFilter = true; @@ -1363,6 +1382,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { updateAccessibilityFocusBehaviorLocked(userState); updateFilterKeyEventsLocked(userState); updateTouchExplorationLocked(userState); + updatePerformGesturesLocked(userState); updateEnhancedWebAccessibilityLocked(userState); updateDisplayColorAdjustmentSettingsLocked(userState); updateMagnificationLocked(userState); @@ -1451,6 +1471,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + private void updatePerformGesturesLocked(UserState userState) { + final int serviceCount = userState.mBoundServices.size(); + for (int i = 0; i < serviceCount; i++) { + Service service = userState.mBoundServices.get(i); + if ((service.mAccessibilityServiceInfo.getCapabilities() + & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0) { + userState.mIsPerformGesturesEnabled = true; + return; + } + } + userState.mIsPerformGesturesEnabled = false; + } + private void updateFilterKeyEventsLocked(UserState userState) { final int serviceCount = userState.mBoundServices.size(); for (int i = 0; i < serviceCount; i++) { @@ -2564,6 +2597,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } @Override + public void sendMotionEvents(int sequence, ParceledListSlice events) { + synchronized (mLock) { + if (mSecurityPolicy.canPerformGestures(this) && (mMotionEventInjector != null)) { + mMotionEventInjector.injectEvents((List<MotionEvent>) events.getList(), + mServiceInterface, sequence); + return; + } + } + try { + mServiceInterface.onPerformGestureResult(sequence, false); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error sending motion event injection failure to " + + mServiceInterface, re); + } + } + + @Override public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) @@ -3734,6 +3784,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { & AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION) != 0; } + public boolean canPerformGestures(Service service) { + return (service.mAccessibilityServiceInfo.getCapabilities() + & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0; + } + private int resolveProfileParentLocked(int userId) { if (userId != mCurrentUserId) { final long identity = Binder.clearCallingIdentity(); @@ -3878,6 +3933,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public boolean mIsEnhancedWebAccessibilityEnabled; public boolean mIsDisplayMagnificationEnabled; public boolean mIsAutoclickEnabled; + public boolean mIsPerformGesturesEnabled; public boolean mIsFilterKeyEventsEnabled; public boolean mHasDisplayColorAdjustment; public boolean mAccessibilityFocusOnlyInActiveWindow; diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java new file mode 100644 index 000000000000..800f0e10cc5e --- /dev/null +++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.accessibility; + +import android.accessibilityservice.IAccessibilityServiceClient; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Slog; +import android.util.SparseArray; +import android.view.InputDevice; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.WindowManagerPolicy; +import android.view.accessibility.AccessibilityEvent; +import com.android.internal.os.SomeArgs; +import com.android.server.accessibility.AccessibilityManagerService.Service; + +import java.util.List; + +/** + * Injects MotionEvents to permit {@code AccessibilityService}s to touch the screen on behalf of + * users. + * + * All methods except {@code injectEvents} must be called only from the main thread. + */ +public class MotionEventInjector implements EventStreamTransformation { + private static final String LOG_TAG = "MotionEventInjector"; + private static final int MESSAGE_SEND_MOTION_EVENT = 1; + private static final int MESSAGE_INJECT_EVENTS = 2; + private static final int MAX_POINTERS = 11; // Non-binding maximum + + private final Handler mHandler; + private final SparseArray<Boolean> mOpenGesturesInProgress = new SparseArray<>(); + + // These two arrays must be the same length + private MotionEvent.PointerProperties[] mPointerProperties = + new MotionEvent.PointerProperties[MAX_POINTERS]; + private MotionEvent.PointerCoords[] mPointerCoords = + new MotionEvent.PointerCoords[MAX_POINTERS]; + private EventStreamTransformation mNext; + private IAccessibilityServiceClient mServiceInterfaceForCurrentGesture; + private int mSequenceForCurrentGesture; + private int mSourceOfInjectedGesture = InputDevice.SOURCE_UNKNOWN; + private boolean mIsDestroyed = false; + + /** + * @param looper A looper on the main thread to use for dispatching new events + */ + public MotionEventInjector(Looper looper) { + mHandler = new Handler(looper, new Callback()); + } + + /** + * Schedule a series of events for injection. These events must comprise a complete, valid + * sequence. All gestures currently in progress will be cancelled, and all {@code downTime} + * and {@code eventTime} fields will be offset by the current time. + * + * @param events The events to inject. Must all be from the same source. + * @param serviceInterface The interface to call back with a result when the gesture is + * either complete or cancelled. + */ + public void injectEvents(List<MotionEvent> events, + IAccessibilityServiceClient serviceInterface, int sequence) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = events; + args.arg2 = serviceInterface; + args.argi1 = sequence; + mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_INJECT_EVENTS, args)); + } + + @Override + public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { + cancelAnyPendingInjectedEvents(); + sendMotionEventToNext(event, rawEvent, policyFlags); + } + + @Override + public void onKeyEvent(KeyEvent event, int policyFlags) { + if (mNext != null) { + mNext.onKeyEvent(event, policyFlags); + } + } + + @Override + public void onAccessibilityEvent(AccessibilityEvent event) { + if (mNext != null) { + mNext.onAccessibilityEvent(event); + } + } + + @Override + public void setNext(EventStreamTransformation next) { + mNext = next; + } + + @Override + public void clearEvents(int inputSource) { + /* + * Reset state for motion events passing through so we won't send a cancel event for + * them. + */ + if (!mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) { + mOpenGesturesInProgress.put(inputSource, false); + } + } + + @Override + public void onDestroy() { + cancelAnyPendingInjectedEvents(); + mIsDestroyed = true; + } + + private void injectEventsMainThread(List<MotionEvent> events, + IAccessibilityServiceClient serviceInterface, int sequence) { + if (mIsDestroyed) { + try { + serviceInterface.onPerformGestureResult(sequence, false); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error sending status with mIsDestroyed to " + serviceInterface, + re); + } + return; + } + cancelAnyPendingInjectedEvents(); + mSourceOfInjectedGesture = events.get(0).getSource(); + cancelAnyGestureInProgress(mSourceOfInjectedGesture); + mServiceInterfaceForCurrentGesture = serviceInterface; + mSequenceForCurrentGesture = sequence; + if (mNext == null) { + notifyService(false); + return; + } + + long startTime = SystemClock.uptimeMillis(); + for (int i = 0; i < events.size(); i++) { + MotionEvent event = events.get(i); + int numPointers = event.getPointerCount(); + if (numPointers > mPointerCoords.length) { + mPointerCoords = new MotionEvent.PointerCoords[numPointers]; + mPointerProperties = new MotionEvent.PointerProperties[numPointers]; + } + for (int j = 0; j < numPointers; j++) { + if (mPointerCoords[j] == null) { + mPointerCoords[j] = new MotionEvent.PointerCoords(); + mPointerProperties[j] = new MotionEvent.PointerProperties(); + } + event.getPointerCoords(j, mPointerCoords[j]); + event.getPointerProperties(j, mPointerProperties[j]); + } + + /* + * MotionEvent doesn't have a setEventTime() method (it carries around history data, + * which could become inconsistent), so we need to obtain a new one. + */ + MotionEvent offsetEvent = MotionEvent.obtain(startTime + event.getDownTime(), + startTime + event.getEventTime(), event.getAction(), numPointers, + mPointerProperties, mPointerCoords, event.getMetaState(), + event.getButtonState(), event.getXPrecision(), event.getYPrecision(), + event.getDeviceId(), event.getEdgeFlags(), event.getSource(), + event.getFlags()); + Message message = mHandler.obtainMessage(MESSAGE_SEND_MOTION_EVENT, offsetEvent); + mHandler.sendMessageDelayed(message, event.getEventTime()); + } + } + + private void sendMotionEventToNext(MotionEvent event, MotionEvent rawEvent, + int policyFlags) { + if (mNext != null) { + mNext.onMotionEvent(event, rawEvent, policyFlags); + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + mOpenGesturesInProgress.put(event.getSource(), true); + } + if ((event.getActionMasked() == MotionEvent.ACTION_UP) + || (event.getActionMasked() == MotionEvent.ACTION_CANCEL)) { + mOpenGesturesInProgress.put(event.getSource(), false); + } + } + } + + private void cancelAnyGestureInProgress(int source) { + if ((mNext != null) && mOpenGesturesInProgress.get(source, false)) { + long now = SystemClock.uptimeMillis(); + MotionEvent cancelEvent = + MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); + sendMotionEventToNext(cancelEvent, cancelEvent, + WindowManagerPolicy.FLAG_PASS_TO_USER); + } + } + + private void cancelAnyPendingInjectedEvents() { + if (mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) { + cancelAnyGestureInProgress(mSourceOfInjectedGesture); + mHandler.removeMessages(MESSAGE_SEND_MOTION_EVENT); + notifyService(false); + } + + } + + private void notifyService(boolean success) { + try { + mServiceInterfaceForCurrentGesture.onPerformGestureResult( + mSequenceForCurrentGesture, success); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error sending motion event injection status to " + + mServiceInterfaceForCurrentGesture, re); + } + } + + private class Callback implements Handler.Callback { + @Override + public boolean handleMessage(Message message) { + if (message.what == MESSAGE_INJECT_EVENTS) { + SomeArgs args = (SomeArgs) message.obj; + injectEventsMainThread((List<MotionEvent>) args.arg1, + (IAccessibilityServiceClient) args.arg2, args.argi1); + args.recycle(); + return true; + } + if (message.what != MESSAGE_SEND_MOTION_EVENT) { + throw new IllegalArgumentException("Unknown message: " + message.what); + } + MotionEvent motionEvent = (MotionEvent) message.obj; + sendMotionEventToNext(motionEvent, motionEvent, + WindowManagerPolicy.FLAG_PASS_TO_USER); + // If the message queue is now empty, then this gesture is complete + if (!mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) { + notifyService(true); + } + return true; + } + } +} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f21eba1460ec..4f75810678a5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -255,7 +255,9 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; +import static android.content.pm.PackageManager.GET_PROVIDERS; import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; +import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -515,9 +517,9 @@ public final class ActivityManagerService extends ActivityManagerNative private Installer mInstaller; /** Run all ActivityStacks through this */ - ActivityStackSupervisor mStackSupervisor; + final ActivityStackSupervisor mStackSupervisor; - ActivityStarter mActivityStarter; + final ActivityStarter mActivityStarter; /** Task stack change listeners. */ private RemoteCallbackList<ITaskStackListener> mTaskStackListeners = @@ -1954,8 +1956,10 @@ public final class ActivityManagerService extends ActivityManagerNative break; } case SYSTEM_USER_UNLOCK_MSG: { - mSystemServiceManager.unlockUser(msg.arg1); - mRecentTasks.cleanupLocked(msg.arg1); + final int userId = msg.arg1; + mSystemServiceManager.unlockUser(userId); + mRecentTasks.cleanupLocked(userId); + installEncryptionUnawareProviders(userId); break; } case SYSTEM_USER_CURRENT_MSG: { @@ -3643,11 +3647,9 @@ public final class ActivityManagerService extends ActivityManagerNative return false; } Intent intent = getHomeIntent(); - ActivityInfo aInfo = - resolveActivityInfo(intent, STOCK_PM_FLAGS, userId); + ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId); if (aInfo != null) { - intent.setComponent(new ComponentName( - aInfo.applicationInfo.packageName, aInfo.name)); + intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name)); // Don't do this if the home app is currently being // instrumented. aInfo = new ActivityInfo(aInfo); @@ -10826,6 +10828,41 @@ public final class ActivityManagerService extends ActivityManagerNative } /** + * When a user is unlocked, we need to install encryption-unaware providers + * belonging to any running apps. + */ + private void installEncryptionUnawareProviders(int userId) { + synchronized (this) { + final int NP = mProcessNames.getMap().size(); + for (int ip = 0; ip < NP; ip++) { + final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip); + final int NA = apps.size(); + for (int ia = 0; ia < NA; ia++) { + final ProcessRecord app = apps.valueAt(ia); + if (app.userId != userId || app.thread == null) continue; + + final int NG = app.pkgList.size(); + for (int ig = 0; ig < NG; ig++) { + try { + final String pkgName = app.pkgList.keyAt(ig); + final PackageInfo pkgInfo = AppGlobals.getPackageManager() + .getPackageInfo(pkgName, + GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE, userId); + if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) { + for (ProviderInfo provInfo : pkgInfo.providers) { + Log.v(TAG, "Installing " + provInfo); + app.thread.scheduleInstallProvider(provInfo); + } + } + } catch (RemoteException ignored) { + } + } + } + } + } + } + + /** * Allows apps to retrieve the MIME type of a URI. * If an app is in the same user as the ContentProvider, or if it is allowed to interact across * users, then it does not need permission to access the ContentProvider. diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index e123dbd3d84a..c44b4cfa7b26 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3368,9 +3368,9 @@ final class ActivityStack { try { ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( destIntent.getComponent(), 0, srec.userId); - int res = mService.mActivityStarter.startActivityLocked(srec.app.thread, destIntent, - null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null, null, - parent.appToken, null, 0, -1, parent.launchedFromUid, + int res = mService.mActivityStarter.startActivityLocked(srec.app.thread, + destIntent, null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null, + null, parent.appToken, null, 0, -1, parent.launchedFromUid, parent.launchedFromPackage, -1, parent.launchedFromUid, 0, null, false, true, null, null, null); foundParentInTask = res == ActivityManager.START_SUCCESS; diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index f712613a2037..cfa44335f6eb 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -32,12 +32,12 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; -import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP; import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT; import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED; import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; +import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; @@ -45,6 +45,7 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; @@ -63,8 +64,8 @@ import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED; import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS; +import static com.android.server.am.EventLogTags.AM_NEW_INTENT; -import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.AppGlobals; @@ -529,7 +530,10 @@ class ActivityStarter { // switch... just dismiss the keyguard now, because we // probably want to see whatever is behind it. mSupervisor.notifyActivityDrawnForKeyguard(); + } else { + launchRecentsAppIfNeeded(stack); } + return err; } @@ -863,6 +867,28 @@ class ActivityStarter { intentActivity.task.setIntent(mStartActivity); } + // This code path leads to delivering a new intent, we want to make sure we schedule it + // as the first operation, in case the activity will be resumed as a result of later + // operations. + if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0 + || mLaunchSingleInstance || mLaunchSingleTask) { + // In this situation we want to remove all activities from the task up to the one + // being started. In most cases this means we are resetting the task to its initial + // state. + final ActivityRecord top = intentActivity.task.performClearTaskLocked( + mStartActivity, mLaunchFlags); + if (top != null) { + if (top.frontOfTask) { + // Activity aliases may mean we use different intents for the top activity, + // so make sure the task now has the identity of the new intent. + top.task.setIntent(mStartActivity); + } + ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task); + top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, + mStartActivity.launchedFromPackage); + } + } + intentActivity = setTargetStackAndMoveToFrontIfNeeded(intentActivity); if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { @@ -904,7 +930,7 @@ class ActivityStarter { && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop || mLaunchSingleTask); if (dontStart) { - ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task); + ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task); // For paranoia, make sure we have correctly resumed the top activity. topStack.mLastPausedActivity = null; if (mDoResume) { @@ -1006,6 +1032,16 @@ class ActivityStarter { return START_SUCCESS; } + private void launchRecentsAppIfNeeded(ActivityStack topStack) { + if (topStack.mStackId == HOME_STACK_ID && mTargetStack.mStackId == DOCKED_STACK_ID) { + // We launch an activity while being in home stack, which means either launcher or + // recents into docked stack. We don't want the launched activity to be alone in a + // docked stack, so we want to immediately launch recents too. + if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch."); + mWindowManager.showRecentApps(); + } + } + private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask, boolean doResume, int startFlags, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) { @@ -1305,20 +1341,9 @@ class ActivityStarter { mReuseTask.setIntent(mStartActivity); } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0 || mLaunchSingleInstance || mLaunchSingleTask) { - // In this situation we want to remove all activities from the task up to the one - // being started. In most cases this means we are resetting the task to its initial - // state. ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity, mLaunchFlags); - if (top != null) { - if (top.frontOfTask) { - // Activity aliases may mean we use different intents for the top activity, - // so make sure the task now has the identity of the new intent. - top.task.setIntent(mStartActivity); - } - ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, top.task); - top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage); - } else { + if (top == null) { // A special case: we need to start the activity because it is not currently // running, and the caller has asked to clear the current task to have this // activity at the top. @@ -1343,7 +1368,7 @@ class ActivityStarter { // desires. if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop) && intentActivity.realActivity.equals(mStartActivity.realActivity)) { - ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, + ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, intentActivity.task); if (intentActivity.frontOfTask) { intentActivity.task.setIntent(mStartActivity); @@ -1439,7 +1464,7 @@ class ActivityStarter { ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags); mKeepCurTransition = true; if (top != null) { - ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, top.task); + ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task); top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage); // For paranoia, make sure we have correctly resumed the top activity. mTargetStack.mLastPausedActivity = null; @@ -1458,7 +1483,7 @@ class ActivityStarter { final TaskRecord task = top.task; task.moveActivityToFrontLocked(top); top.updateOptionsLocked(mOptions); - ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, task); + ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, task); top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage); mTargetStack.mLastPausedActivity = null; if (mDoResume) { @@ -1495,7 +1520,7 @@ class ActivityStarter { if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) { if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop || mLaunchSingleTask) { - ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task); + ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task); if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { // We don't need to start a new activity, and the client said not to do // anything if that is the case, so this is it! diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 4eabe3684e4f..3530d80577c7 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -613,9 +613,10 @@ public class JobSchedulerService extends com.android.server.SystemService if (periodicToReschedule.hasDeadlineConstraint()) { runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0L); } - long newEarliestRunTimeElapsed = elapsedNow + runEarly; + long flex = periodicToReschedule.getJob().getFlexMillis(); long period = periodicToReschedule.getJob().getIntervalMillis(); - long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period; + long newLatestRuntimeElapsed = elapsedNow + runEarly + period; + long newEarliestRunTimeElapsed = newLatestRuntimeElapsed - flex; if (DEBUG) { Slog.v(TAG, "Rescheduling executed periodic. New execution window [" + diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java index 472e8f6ff06c..b8aa9dd7d156 100644 --- a/services/core/java/com/android/server/job/JobStore.java +++ b/services/core/java/com/android/server/job/JobStore.java @@ -397,6 +397,7 @@ public class JobStore { if (jobStatus.getJob().isPeriodic()) { out.startTag(null, XML_TAG_PERIODIC); out.attribute(null, "period", Long.toString(job.getIntervalMillis())); + out.attribute(null, "flex", Long.toString(job.getFlexMillis())); } else { out.startTag(null, XML_TAG_ONEOFF); } @@ -594,13 +595,17 @@ public class JobStore { String val = parser.getAttributeValue(null, "period"); final long periodMillis = Long.valueOf(val); jobBuilder.setPeriodic(periodMillis); - // As a sanity check, cap the recreated run time to be no later than 2 periods + val = parser.getAttributeValue(null, "flex"); + final long flexMillis = (val != null) ? Long.valueOf(val) : periodMillis; + // As a sanity check, cap the recreated run time to be no later than flex+period // from now. This is the latest the periodic could be pushed out. This could - // happen if the periodic ran early (at the start of its period), and then the + // happen if the periodic ran early (at flex time before period), and then the // device rebooted. - if (elapsedRuntimes.second > elapsedNow + 2 * periodMillis) { - final long clampedEarlyRuntimeElapsed = elapsedNow + periodMillis; - final long clampedLateRuntimeElapsed = elapsedNow + 2 * periodMillis; + if (elapsedRuntimes.second > elapsedNow + periodMillis + flexMillis) { + final long clampedLateRuntimeElapsed = elapsedNow + flexMillis + + periodMillis; + final long clampedEarlyRuntimeElapsed = clampedLateRuntimeElapsed + - flexMillis; Slog.w(TAG, String.format("Periodic job for uid='%d' persisted run-time is" + " too big [%s, %s]. Clamping to [%s,%s]", 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 c02611f4fdce..060a93ef8ed9 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -96,8 +96,8 @@ public class JobStatus { final long elapsedNow = SystemClock.elapsedRealtime(); if (job.isPeriodic()) { - earliestRunTimeElapsedMillis = elapsedNow; latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis(); + earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis(); } else { earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ? elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index e787eda171ea..018bf2d2cb27 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -28,6 +28,7 @@ import static android.service.notification.NotificationAssistantService.REASON_L import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL_ALL; import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_BANNED; import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED; +import static android.service.notification.NotificationAssistantService.REASON_TOPIC_BANNED; import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH; @@ -741,7 +742,7 @@ public class NotificationManagerService extends SystemService { for (String pkgName : pkgList) { if (cancelNotifications) { cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart, - changeUserId, REASON_PACKAGE_CHANGED, null); + changeUserId, REASON_PACKAGE_CHANGED, null, null); } } } @@ -774,7 +775,7 @@ public class NotificationManagerService extends SystemService { int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); if (userHandle >= 0) { cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle, - REASON_USER_STOPPED, null); + REASON_USER_STOPPED, null, null); } } else if (action.equals(Intent.ACTION_USER_PRESENT)) { // turn off LED when user passes through lock screen @@ -1051,7 +1052,7 @@ public class NotificationManagerService extends SystemService { // Now, cancel any outstanding notifications that are part of a just-disabled app if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid), - REASON_PACKAGE_BANNED, null); + REASON_PACKAGE_BANNED, null, null); } } @@ -1209,7 +1210,7 @@ public class NotificationManagerService extends SystemService { // running foreground services. cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId, - REASON_APP_CANCEL_ALL, null); + REASON_APP_CANCEL_ALL, null, null); } @Override @@ -1266,6 +1267,11 @@ public class NotificationManagerService extends SystemService { public void setTopicImportance(String pkg, int uid, Notification.Topic topic, int importance) { enforceSystemOrSystemUI("Caller not system or systemui"); + if (NotificationListenerService.Ranking.IMPORTANCE_NONE == importance) { + cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, + UserHandle.getUserId(uid), + REASON_TOPIC_BANNED, topic, null); + } mRankingHelper.setTopicImportance(pkg, uid, topic, importance); savePolicyFile(); } @@ -2284,8 +2290,9 @@ public class NotificationManagerService extends SystemService { mRankingHelper.extractSignals(r); savePolicyFile(); - // blocked apps - if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) { + // blocked apps/topics + if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE + || !noteNotificationOp(pkg, callingUid)) { if (!isSystemNotification) { Slog.e(TAG, "Suppressing notification from package " + pkg + " by user request."); @@ -3067,11 +3074,11 @@ public class NotificationManagerService extends SystemService { } /** - * Cancels all notifications from a given package that have all of the + * Cancels all notifications from a given package or topic that have all of the * {@code mustHaveFlags}. */ boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, - int mustNotHaveFlags, boolean doit, int userId, int reason, + int mustNotHaveFlags, boolean doit, int userId, int reason, Notification.Topic topic, ManagedServiceInfo listener) { String listenerName = listener == null ? null : listener.component.toShortString(); EventLogTags.writeNotificationCancelAll(callingUid, callingPid, @@ -3099,6 +3106,10 @@ public class NotificationManagerService extends SystemService { if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { continue; } + if (topic != null + && !topic.getId().equals(r.getNotification().getTopic().getId())) { + continue; + } if (canceledNotifications == null) { canceledNotifications = new ArrayList<>(); } diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index f1fd42c69101..ce4ecd39cd58 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -423,14 +423,16 @@ public class RankingHelper implements RankingConfig { /** * Sets the default importance for all new topics that appear in the future, and resets - * the importance of all current topics. + * the importance of all current topics (unless the app is being blocked). */ @Override public void setAppImportance(String pkgName, int uid, int importance) { final Record r = getOrCreateRecord(pkgName, uid); r.importance = importance; - for (Topic t : r.topics.values()) { - t.importance = importance; + if (Ranking.IMPORTANCE_NONE != importance) { + for (Topic t : r.topics.values()) { + t.importance = importance; + } } updateConfig(); } @@ -483,7 +485,9 @@ public class RankingHelper implements RankingConfig { pw.print(prefix); pw.println("per-package config:"); } + pw.println("Records:"); dumpRecords(pw, prefix, filter, mRecords); + pw.println("Restored without uid:"); dumpRecords(pw, prefix, filter, mRestoredWithoutUids); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 870ae892d435..e3ed0c136d56 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -318,6 +318,8 @@ public class PackageManagerService extends IPackageManager.Stub { static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false; + private static final boolean DISABLE_EPHEMERAL_APPS = true; + private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; private static final int NFC_UID = Process.NFC_UID; @@ -3119,7 +3121,7 @@ public class PackageManagerService extends IPackageManager.Stub { /** * Update given flags based on encryption status of current user. */ - private int updateFlagsForEncryption(int flags, int userId) { + private int updateFlags(int flags, int userId) { if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE | PackageManager.MATCH_ENCRYPTION_AWARE)) != 0) { // Caller expressed an explicit opinion about what encryption @@ -3133,6 +3135,12 @@ public class PackageManagerService extends IPackageManager.Stub { flags |= PackageManager.MATCH_ENCRYPTION_AWARE; } } + + // Safe mode means we should ignore any third-party apps + if (mSafeMode) { + flags |= PackageManager.MATCH_SYSTEM_ONLY; + } + return flags; } @@ -3160,7 +3168,7 @@ public class PackageManagerService extends IPackageManager.Stub { Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie + " with flags 0x" + Integer.toHexString(flags), new Throwable()); } - return updateFlagsForEncryption(flags, userId); + return updateFlags(flags, userId); } /** @@ -3192,7 +3200,7 @@ public class PackageManagerService extends IPackageManager.Stub { Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie + " with flags 0x" + Integer.toHexString(flags), new Throwable()); } - return updateFlagsForEncryption(flags, userId); + return updateFlags(flags, userId); } /** @@ -4469,6 +4477,9 @@ public class PackageManagerService extends IPackageManager.Stub { private boolean isEphemeralAllowed( Intent intent, List<ResolveInfo> resolvedActivites, int userId) { // Short circuit and return early if possible. + if (DISABLE_EPHEMERAL_APPS) { + return false; + } final int callingUser = UserHandle.getCallingUserId(); if (callingUser != UserHandle.USER_SYSTEM) { return false; @@ -5803,6 +5814,10 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ParceledListSlice<EphemeralApplicationInfo> getEphemeralApplications(int userId) { + if (DISABLE_EPHEMERAL_APPS) { + return null; + } + mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS, "getEphemeralApplications"); enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, @@ -5821,6 +5836,10 @@ public class PackageManagerService extends IPackageManager.Stub { public boolean isEphemeralApplication(String packageName, int userId) { enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "isEphemeral"); + if (DISABLE_EPHEMERAL_APPS) { + return false; + } + if (!isCallerSameApp(packageName)) { return false; } @@ -5835,6 +5854,10 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public byte[] getEphemeralApplicationCookie(String packageName, int userId) { + if (DISABLE_EPHEMERAL_APPS) { + return null; + } + enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getCookie"); if (!isCallerSameApp(packageName)) { @@ -5848,6 +5871,10 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public boolean setEphemeralApplicationCookie(String packageName, byte[] cookie, int userId) { + if (DISABLE_EPHEMERAL_APPS) { + return true; + } + enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "setCookie"); if (!isCallerSameApp(packageName)) { @@ -5861,6 +5888,10 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public Bitmap getEphemeralApplicationIcon(String packageName, int userId) { + if (DISABLE_EPHEMERAL_APPS) { + return null; + } + mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS, "getEphemeralApplicationIcon"); enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, @@ -5916,8 +5947,6 @@ public class PackageManagerService extends IPackageManager.Stub { : null; return ps != null && mSettings.isEnabledAndMatchLPr(provider.info, flags, userId) - && (!mSafeMode || (provider.info.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) != 0) ? PackageParser.generateProviderInfo(provider, flags, ps.readUserState(userId), userId) : null; @@ -5972,9 +6001,7 @@ public class PackageManagerService extends IPackageManager.Stub { && (processName == null || (p.info.processName.equals(processName) && UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) - && mSettings.isEnabledAndMatchLPr(p.info, flags, userId) - && (!mSafeMode - || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) { + && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) { if (finalList == null) { finalList = new ArrayList<ProviderInfo>(3); } @@ -9240,10 +9267,6 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } final PackageParser.Activity activity = info.activity; - if (mSafeMode && (activity.info.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) == 0) { - return null; - } PackageSetting ps = (PackageSetting) activity.owner.mExtras; if (ps == null) { return null; @@ -9464,10 +9487,6 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } final PackageParser.Service service = info.service; - if (mSafeMode && (service.info.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) == 0) { - return null; - } PackageSetting ps = (PackageSetting) service.owner.mExtras; if (ps == null) { return null; @@ -9687,10 +9706,6 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } final PackageParser.Provider provider = info.provider; - if (mSafeMode && (provider.info.applicationInfo.flags - & ApplicationInfo.FLAG_SYSTEM) == 0) { - return null; - } PackageSetting ps = (PackageSetting) provider.owner.mExtras; if (ps == null) { return null; diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 3f9ce7a64aae..1a79d3c3e733 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -3799,63 +3799,11 @@ final class Settings { } boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) { - return isEnabledLPr(componentInfo, flags, userId) - && isMatchLPr(componentInfo, flags); - } - - private boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) { - if ((flags & MATCH_DISABLED_COMPONENTS) != 0) { - return true; - } - final PackageSetting packageSettings = mPackages.get(componentInfo.packageName); - if (PackageManagerService.DEBUG_SETTINGS) { - Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = " - + componentInfo.packageName + " componentName = " + componentInfo.name); - Log.v(PackageManagerService.TAG, "enabledComponents: " - + compToString(packageSettings.getEnabledComponents(userId))); - Log.v(PackageManagerService.TAG, "disabledComponents: " - + compToString(packageSettings.getDisabledComponents(userId))); - } - if (packageSettings == null) { - return false; - } - PackageUserState ustate = packageSettings.readUserState(userId); - if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) != 0) { - if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { - return true; - } - } - if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED - || ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_USER - || ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED - || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled - && ustate.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) { - return false; - } - if (ustate.enabledComponents != null - && ustate.enabledComponents.contains(componentInfo.name)) { - return true; - } - if (ustate.disabledComponents != null - && ustate.disabledComponents.contains(componentInfo.name)) { - return false; - } - return componentInfo.enabled; - } - - private boolean isMatchLPr(ComponentInfo componentInfo, int flags) { - if ((flags & MATCH_SYSTEM_ONLY) != 0) { - final PackageSetting ps = mPackages.get(componentInfo.packageName); - if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { - return false; - } - } + final PackageSetting ps = mPackages.get(componentInfo.packageName); + if (ps == null) return false; - final boolean matchesUnaware = ((flags & MATCH_ENCRYPTION_UNAWARE) != 0) - && !componentInfo.encryptionAware; - final boolean matchesAware = ((flags & MATCH_ENCRYPTION_AWARE) != 0) - && componentInfo.encryptionAware; - return matchesUnaware || matchesAware; + final PackageUserState userState = ps.readUserState(userId); + return userState.isMatch(componentInfo, flags); } String getInstallerPackageNameLPr(String packageName) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index f13d964e1e1b..de1c1ea091df 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3788,7 +3788,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // size. We need to do this directly, instead of relying on // it to bubble up from the nav bar, because this needs to // change atomically with screen rotations. - mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight); + mNavigationBarOnBottom = isNavigationBarOnBottom(displayWidth, displayHeight); if (mNavigationBarOnBottom) { // It's a system nav bar or a portrait screen; nav bar goes on bottom. int top = displayHeight - overscanBottom @@ -3859,6 +3859,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + private boolean isNavigationBarOnBottom(int displayWidth, int displayHeight) { + return !mNavigationBarCanMove || displayWidth < displayHeight; + } + /** {@inheritDoc} */ @Override public int getSystemDecorLayerLw() { @@ -5931,6 +5935,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + @Override + public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight, + Rect outInsets) { + outInsets.setEmpty(); + if (mStatusBar != null) { + outInsets.top = mStatusBarHeight; + } + if (mNavigationBar != null) { + if (isNavigationBarOnBottom(displayWidth, displayHeight)) { + outInsets.bottom = getNavigationBarHeight(displayRotation, mUiMode); + } else { + outInsets.right = getNavigationBarWidth(displayRotation, mUiMode); + } + } + } + void sendCloseSystemWindows() { PhoneWindow.sendCloseSystemWindows(mContext, null); } diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java index 7be0eadf895e..c3a6f5d2f637 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java @@ -291,15 +291,24 @@ public class WebViewUpdateService extends SystemService { // If the user has chosen provider, use that for (WebViewProviderInfo provider : providers) { - if (provider.packageName.equals(userChosenProvider)) { + if (provider.packageName.equals(userChosenProvider) && provider.isEnabled()) { return provider.getPackageInfo(); } } - // User did not choose, or the choice failed, use the most stable provider available + // User did not choose, or the choice failed; use the most stable provider that is + // enabled and available by default (not through user choice). + for (WebViewProviderInfo provider : providers) { + if (provider.isAvailableByDefault() && provider.isEnabled()) { + return provider.getPackageInfo(); + } + } + + // Could not find any enabled package either, use the most stable provider. for (WebViewProviderInfo provider : providers) { return provider.getPackageInfo(); } + mAnyWebViewInstalled = false; throw new WebViewFactory.MissingWebViewPackageException( "Could not find a loadable WebView package"); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 51787b066859..a9025bda2fbc 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -393,7 +393,7 @@ class DisplayContent { } mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE); } - if (task.isDockedInEffect() && !task.isResizeable()) { + if (task.isTwoFingerScrollMode()) { stack.getBounds(mTmpRect); mNonResizeableRegion.op(mTmpRect, Region.Op.UNION); break; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index b4ddebc7c346..6bb3e20727e8 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -558,8 +558,9 @@ class Task implements DimLayer.DimLayerUser { } boolean isResizeableByDockedStack() { - return mStack != null && getDisplayContent().getDockedStackLocked() != null && - StackId.isTaskResizeableByDockedStack(mStack.mStackId); + final DisplayContent displayContent = getDisplayContent(); + return displayContent != null && displayContent.getDockedStackLocked() != null + && mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId); } /** @@ -570,6 +571,10 @@ class Task implements DimLayer.DimLayerUser { return inDockedWorkspace() || isResizeableByDockedStack(); } + boolean isTwoFingerScrollMode() { + return isDockedInEffect() && !isResizeable(); + } + WindowState getTopVisibleAppMainWindow() { final AppWindowToken token = getTopVisibleAppToken(); return token != null ? token.findMainWindow() : null; diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index fc6ad70513b1..e75780f6a095 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -18,6 +18,7 @@ package com.android.server.wm; import android.app.ActivityManager.StackId; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Rect; import android.os.Debug; import android.util.EventLog; @@ -26,6 +27,9 @@ import android.util.SparseArray; import android.view.DisplayInfo; import android.view.Surface; +import com.android.internal.policy.DividerSnapAlgorithm; +import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; +import com.android.internal.policy.DockedDividerUtils; import com.android.server.EventLogTags; import java.io.PrintWriter; @@ -126,7 +130,7 @@ public class TaskStack implements DimLayer.DimLayerUser { Configuration config = configs.get(task.mTaskId); if (config != null) { Rect bounds = taskBounds.get(task.mTaskId); - if (!task.isResizeable() && task.isDockedInEffect()) { + if (task.isTwoFingerScrollMode()) { // This is a non-resizeable task that's docked (or side-by-side to the docked // stack). It might have been scrolled previously, and after the stack resizing, // it might no longer fully cover the stack area. @@ -245,19 +249,66 @@ public class TaskStack implements DimLayer.DimLayerUser { setBounds(null); } else { mTmpRect2.set(mBounds); - mDisplayContent.rotateBounds( - mRotation, mDisplayContent.getDisplayInfo().rotation, mTmpRect2); - if (setBounds(mTmpRect2)) { - // Post message to inform activity manager of the bounds change simulating - // a one-way call. We do this to prevent a deadlock between window manager - // lock and activity manager lock been held. - mService.mH.sendMessage(mService.mH.obtainMessage( - RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mBounds)); + final int newRotation = mDisplayContent.getDisplayInfo().rotation; + if (mRotation == newRotation) { + setBounds(mTmpRect2); } + + // If the rotation changes, we'll handle it in updateBoundsAfterRotation } } } + /** + * Updates the bounds after rotating the screen. We can't handle it in + * {@link #updateDisplayInfo} because at that point the configuration might not be fully updated + * yet. + */ + void updateBoundsAfterRotation() { + final int newRotation = getDisplayInfo().rotation; + mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2); + if (mStackId == DOCKED_STACK_ID) { + snapDockedStackAfterRotation(mTmpRect2); + } + + // Post message to inform activity manager of the bounds change simulating + // a one-way call. We do this to prevent a deadlock between window manager + // lock and activity manager lock been held. + mService.mH.sendMessage(mService.mH.obtainMessage( + RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2)); + } + + /** + * Snaps the bounds after rotation to the closest snap target for the docked stack. + */ + private void snapDockedStackAfterRotation(Rect outBounds) { + + // Calculate the current position. + final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); + final int dividerSize = mService.getDefaultDisplayContentLocked() + .getDockedDividerController().getContentWidth(); + final int dockSide = getDockSide(outBounds); + final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds, + dockSide, dividerSize); + final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth; + final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight; + + // Snap the position to a target. + final int rotation = displayInfo.rotation; + final int orientation = mService.mCurConfiguration.orientation; + mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds); + final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm( + mService.mContext.getResources(), + 0 /* minFlingVelocityPxPerSecond */, displayWidth, displayHeight, + dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds); + final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition); + + // Recalculate the bounds based on the position of the target. + DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide, + outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight, + dividerSize); + } + boolean isAnimating() { for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; @@ -682,6 +733,10 @@ public class TaskStack implements DimLayer.DimLayerUser { * information which side of the screen was the dock anchored. */ int getDockSide() { + return getDockSide(mBounds); + } + + int getDockSide(Rect bounds) { if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) { return DOCKED_INVALID; } @@ -692,14 +747,14 @@ public class TaskStack implements DimLayer.DimLayerUser { final int orientation = mService.mCurConfiguration.orientation; if (orientation == Configuration.ORIENTATION_PORTRAIT) { // Portrait mode, docked either at the top or the bottom. - if (mBounds.top - mTmpRect.top < mTmpRect.bottom - mBounds.bottom) { + if (bounds.top - mTmpRect.top < mTmpRect.bottom - bounds.bottom) { return DOCKED_TOP; } else { return DOCKED_BOTTOM; } } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { // Landscape mode, docked either on the left or on the right. - if (mBounds.left - mTmpRect.left < mTmpRect.right - mBounds.right) { + if (bounds.left - mTmpRect.left < mTmpRect.right - bounds.right) { return DOCKED_LEFT; } else { return DOCKED_RIGHT; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f858abe9b031..685df25910d6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1990,6 +1990,10 @@ public class WindowManagerService extends IWindowManager.Stub } } + // If the window is being added to a task that's docked but non-resizeable, + // we need to update this new window's scroll position when it's added. + win.applyScrollIfNeeded(); + if (type == TYPE_DOCK_DIVIDER) { getDefaultDisplayContentLocked().getDockedDividerController().setWindow(win); } @@ -2977,7 +2981,7 @@ public class WindowManagerService extends IWindowManager.Stub + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets); Animation a = mAppTransition.loadAnimation(lp, transit, enter, mCurConfiguration.orientation, frame, insets, surfaceInsets, isVoiceInteraction, - freeform, atoken.mTask.mTaskId); + !fullscreen, atoken.mTask.mTaskId); if (a != null) { if (DEBUG_ANIM) { RuntimeException e = null; @@ -3523,6 +3527,7 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override public void setNewConfiguration(Configuration config) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "setNewConfiguration()")) { @@ -3536,10 +3541,20 @@ public class WindowManagerService extends IWindowManager.Stub mWaitingForConfig = false; mLastFinishedFreezeSource = "new-config"; } + if (orientationChanged) { + updateTaskStackBoundsAfterRotation(); + } mWindowPlacerLocked.performSurfacePlacement(); } } + private void updateTaskStackBoundsAfterRotation() { + for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) { + final TaskStack stack = mStackIdToStack.valueAt(stackNdx); + stack.updateBoundsAfterRotation(); + } + } + @Override public void setAppOrientation(IApplicationToken token, int requestedOrientation) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index b7fd60f1c201..058fa67a5e4a 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1458,15 +1458,24 @@ final class WindowState implements WindowManagerPolicy.WindowState { } boolean inDockedWorkspace() { - Task task = getTask(); + final Task task = getTask(); return task != null && task.inDockedWorkspace(); } boolean isDockedInEffect() { - Task task = getTask(); + final Task task = getTask(); return task != null && task.isDockedInEffect(); } + void applyScrollIfNeeded() { + final Task task = getTask(); + if (task != null && task.isTwoFingerScrollMode()) { + task.getDimBounds(mTmpRect); + mXOffset = mTmpRect.left; + mYOffset = mTmpRect.top; + } + } + int getTouchableRegion(Region region, int flags) { final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0; if (modal && mAppToken != null) { diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java index dabf706bc976..216603cad5ee 100644 --- a/telecomm/java/android/telecom/VideoProfile.java +++ b/telecomm/java/android/telecom/VideoProfile.java @@ -16,13 +16,23 @@ package android.telecom; +import android.annotation.IntDef; import android.os.Parcel; import android.os.Parcelable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Represents attributes of video calls. */ public class VideoProfile implements Parcelable { + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({QUALITY_UNKNOWN, QUALITY_HIGH, QUALITY_MEDIUM, QUALITY_LOW, QUALITY_DEFAULT}) + public @interface VideoQuality {} + /** * "Unknown" video quality. * @hide @@ -48,6 +58,14 @@ public class VideoProfile implements Parcelable { */ public static final int QUALITY_DEFAULT = 4; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + flag = true, + value = {STATE_AUDIO_ONLY, STATE_TX_ENABLED, STATE_RX_ENABLED, STATE_BIDIRECTIONAL, + STATE_PAUSED}) + public @interface VideoState {} + /** * Used when answering or dialing a call to indicate that the call does not have a video * component. @@ -107,7 +125,7 @@ public class VideoProfile implements Parcelable { * * @param videoState The video state. */ - public VideoProfile(int videoState) { + public VideoProfile(@VideoState int videoState) { this(videoState, QUALITY_DEFAULT); } @@ -117,7 +135,7 @@ public class VideoProfile implements Parcelable { * @param videoState The video state. * @param quality The video quality. */ - public VideoProfile(int videoState, int quality) { + public VideoProfile(@VideoState int videoState, @VideoQuality int quality) { mVideoState = videoState; mQuality = quality; } @@ -130,6 +148,7 @@ public class VideoProfile implements Parcelable { * {@link VideoProfile#STATE_RX_ENABLED}, * {@link VideoProfile#STATE_PAUSED}. */ + @VideoState public int getVideoState() { return mVideoState; } @@ -139,6 +158,7 @@ public class VideoProfile implements Parcelable { * Valid values: {@link VideoProfile#QUALITY_HIGH}, {@link VideoProfile#QUALITY_MEDIUM}, * {@link VideoProfile#QUALITY_LOW}, {@link VideoProfile#QUALITY_DEFAULT}. */ + @VideoQuality public int getQuality() { return mQuality; } @@ -211,7 +231,7 @@ public class VideoProfile implements Parcelable { * @param videoState The video state. * @return String representation of the video state. */ - public static String videoStateToString(int videoState) { + public static String videoStateToString(@VideoState int videoState) { StringBuilder sb = new StringBuilder(); sb.append("Audio"); @@ -240,7 +260,7 @@ public class VideoProfile implements Parcelable { * @param videoState The video state. * @return {@code True} if the video state is audio only, {@code false} otherwise. */ - public static boolean isAudioOnly(int videoState) { + public static boolean isAudioOnly(@VideoState int videoState) { return !hasState(videoState, VideoProfile.STATE_TX_ENABLED) && !hasState(videoState, VideoProfile.STATE_RX_ENABLED); } @@ -251,7 +271,7 @@ public class VideoProfile implements Parcelable { * @param videoState The video state. * @return {@code True} if video transmission or reception is enabled, {@code false} otherwise. */ - public static boolean isVideo(int videoState) { + public static boolean isVideo(@VideoState int videoState) { return hasState(videoState, VideoProfile.STATE_TX_ENABLED) || hasState(videoState, VideoProfile.STATE_RX_ENABLED) || hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL); @@ -263,7 +283,7 @@ public class VideoProfile implements Parcelable { * @param videoState The video state. * @return {@code True} if video transmission is enabled, {@code false} otherwise. */ - public static boolean isTransmissionEnabled(int videoState) { + public static boolean isTransmissionEnabled(@VideoState int videoState) { return hasState(videoState, VideoProfile.STATE_TX_ENABLED); } @@ -273,7 +293,7 @@ public class VideoProfile implements Parcelable { * @param videoState The video state. * @return {@code True} if video reception is enabled, {@code false} otherwise. */ - public static boolean isReceptionEnabled(int videoState) { + public static boolean isReceptionEnabled(@VideoState int videoState) { return hasState(videoState, VideoProfile.STATE_RX_ENABLED); } @@ -283,7 +303,7 @@ public class VideoProfile implements Parcelable { * @param videoState The video state. * @return {@code True} if the video is bi-directional, {@code false} otherwise. */ - public static boolean isBidirectional(int videoState) { + public static boolean isBidirectional(@VideoState int videoState) { return hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL); } @@ -293,7 +313,7 @@ public class VideoProfile implements Parcelable { * @param videoState The video state. * @return {@code True} if the video is paused, {@code false} otherwise. */ - public static boolean isPaused(int videoState) { + public static boolean isPaused(@VideoState int videoState) { return hasState(videoState, VideoProfile.STATE_PAUSED); } @@ -304,7 +324,7 @@ public class VideoProfile implements Parcelable { * @param state The state to check. * @return {@code True} if the state is set. */ - private static boolean hasState(int videoState, int state) { + private static boolean hasState(@VideoState int videoState, @VideoState int state) { return (videoState & state) == state; } diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 01583f56ef73..81aa6c6eec3c 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -322,21 +322,25 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** @hide */ @Override public byte[] getEphemeralCookie() { return new byte[0]; } + /** @hide */ @Override public boolean isEphemeralApplication() { return false; } + /** @hide */ @Override public int getEphemeralCookieMaxSizeBytes() { return 0; } + /** @hide */ @Override public boolean setEphemeralCookie(@NonNull byte[] cookie) { return false; diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java index fecfdf98d0e7..3a30230833ed 100644 --- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java +++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java @@ -175,7 +175,7 @@ public class NotificationTestList extends TestActivity .setTopic(new Notification.Topic("hello", "Hello")) .build(); - mNM.notify(999, n); + mNM.notify(70, n); } }, @@ -194,7 +194,7 @@ public class NotificationTestList extends TestActivity .setStyle(picture) .build(); - mNM.notify(9999, n); + mNM.notify(71, n); } }, new Test("with topic Bananas") { @@ -211,10 +211,28 @@ public class NotificationTestList extends TestActivity .setTopic(new Notification.Topic("bananas", "Bananas")) .build(); - mNM.notify(999, n); + mNM.notify(72, n); } }, + new Test("with delete intent") { + public void run() { + Notification.BigTextStyle bigText = new Notification.BigTextStyle(); + bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n"); + Notification n = new Notification.Builder(NotificationTestList.this) + .setSmallIcon(R.drawable.icon1) + .setStyle(bigText) + .setWhen(mActivityCreateTime) + .setContentTitle("bananananana") + .setContentText("This is a banana!!!") + .setTopic(new Notification.Topic("bananas", "Bananas")) + .setDeleteIntent(makeIntent2()) + .build(); + + mNM.notify(73, n); + } + }, + new Test("Whens") { public void run() { diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index e1f9642d27d7..5e7d3ec4c1e0 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -582,10 +582,15 @@ bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* out if (formatted && translateable) { if (!util::verifyJavaStringFormat(*stringValue->value)) { - mDiag->error(DiagMessage(outResource->source) - << "multiple substitutions specified in non-positional format; " - "did you mean to add the formatted=\"false\" attribute?"); - return false; + DiagMessage msg(outResource->source); + msg << "multiple substitutions specified in non-positional format; " + "did you mean to add the formatted=\"false\" attribute?"; + if (mOptions.errorOnPositionalArguments) { + mDiag->error(msg); + return false; + } + + mDiag->warn(msg); } } diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index 9ad749e27dbc..51cbbe19384e 100644 --- a/tools/aapt2/ResourceParser.h +++ b/tools/aapt2/ResourceParser.h @@ -44,6 +44,11 @@ struct ResourceParserOptions { * Whether the default setting for this parser is to allow translation. */ bool translatable = true; + + /** + * Whether positional arguments in formatted strings are treated as errors or warnings. + */ + bool errorOnPositionalArguments = true; }; /* diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp index b3b0f65e54da..c78670fbc20d 100644 --- a/tools/aapt2/compile/Compile.cpp +++ b/tools/aapt2/compile/Compile.cpp @@ -107,6 +107,7 @@ struct CompileOptions { Maybe<std::string> resDir; std::vector<std::u16string> products; bool pseudolocalize = false; + bool legacyMode = false; bool verbose = false; }; @@ -192,6 +193,7 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options, ResourceParserOptions parserOptions; parserOptions.products = options.products; + parserOptions.errorOnPositionalArguments = !options.legacyMode; // If the filename includes donottranslate, then the default translatable is false. parserOptions.translatable = pathData.name.find(u"donottranslate") == std::string::npos; @@ -438,6 +440,8 @@ int compile(const std::vector<StringPiece>& args) { .optionalFlag("--dir", "Directory to scan for resources", &options.resDir) .optionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales " "(en-XA and ar-XB)", &options.pseudolocalize) + .optionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings", + &options.legacyMode) .optionalSwitch("-v", "Enables verbose logging", &options.verbose); if (!flags.parse("aapt2 compile", args, &std::cerr)) { return 1; diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp index 652e52fa0a67..8a87d9691b5d 100644 --- a/tools/aapt2/link/Link.cpp +++ b/tools/aapt2/link/Link.cpp @@ -228,29 +228,53 @@ public: return {}; } + /** + * Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked. + * Postcondition: ResourceTable has only one package left. All others are stripped, or there + * is an error and false is returned. + */ bool verifyNoExternalPackages() { + auto isExtPackageFunc = [&](const std::unique_ptr<ResourceTablePackage>& pkg) -> bool { + return mContext.getCompilationPackage() != pkg->name || + !pkg->id || + pkg->id.value() != mContext.getPackageId(); + }; + bool error = false; for (const auto& package : mFinalTable.packages) { - if (mContext.getCompilationPackage() != package->name || - !package->id || package->id.value() != mContext.getPackageId()) { + if (isExtPackageFunc(package)) { // We have a package that is not related to the one we're building! for (const auto& type : package->types) { for (const auto& entry : type->entries) { + ResourceNameRef resName(package->name, type->type, entry->name); + for (const auto& configValue : entry->values) { - mContext.getDiagnostics()->error( - DiagMessage(configValue.value->getSource()) - << "defined resource '" - << ResourceNameRef(package->name, - type->type, - entry->name) - << "' for external package '" - << package->name << "'"); - error = true; + // Special case the occurrence of an ID that is being generated for the + // 'android' package. This is due to legacy reasons. + if (valueCast<Id>(configValue.value.get()) && + package->name == u"android") { + mContext.getDiagnostics()->warn( + DiagMessage(configValue.value->getSource()) + << "generated id '" << resName + << "' for external package '" << package->name + << "'"); + } else { + mContext.getDiagnostics()->error( + DiagMessage(configValue.value->getSource()) + << "defined resource '" << resName + << "' for external package '" << package->name + << "'"); + error = true; + } } } } } } + + auto newEndIter = std::remove_if(mFinalTable.packages.begin(), mFinalTable.packages.end(), + isExtPackageFunc); + mFinalTable.packages.erase(newEndIter, mFinalTable.packages.end()); return !error; } diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java index 31dd3d943769..db4c6dc68b77 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java @@ -327,12 +327,19 @@ public final class BridgeTypedArray extends TypedArray { return null; } - // let the framework inflate the ColorStateList from the XML file. - File f = new File(value); - if (f.isFile()) { - try { - XmlPullParser parser = ParserFactory.create(f); + try { + // Get the state list file content from callback to parse PSI file + XmlPullParser parser = mContext.getLayoutlibCallback().getXmlFileParser(value); + if (parser == null) { + // If used with a version of Android Studio that does not implement getXmlFileParser + // fall back to reading the file from disk + File f = new File(value); + if (f.isFile()) { + parser = ParserFactory.create(f); + } + } + if (parser != null) { BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( parser, mContext, resValue.isFramework()); try { @@ -341,18 +348,18 @@ public final class BridgeTypedArray extends TypedArray { } finally { blockParser.ensurePopped(); } - } catch (XmlPullParserException e) { - Bridge.getLog().error(LayoutLog.TAG_BROKEN, - "Failed to configure parser for " + value, e, null); - return null; - } catch (Exception e) { - // this is an error and not warning since the file existence is checked before - // attempting to parse it. - Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ, - "Failed to parse file " + value, e, null); - - return null; } + } catch (XmlPullParserException e) { + Bridge.getLog().error(LayoutLog.TAG_BROKEN, + "Failed to configure parser for " + value, e, null); + return null; + } catch (Exception e) { + // this is an error and not warning since the file existence is checked before + // attempting to parse it. + Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ, + "Failed to parse file " + value, e, null); + + return null; } try { diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java index 60514b658649..8d5863be918b 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java @@ -122,4 +122,35 @@ import java.util.Set; /*package*/ static boolean nativeIsSeekable(FileDescriptor fd) { return true; } + + /** + * Set the newly decoded bitmap's density based on the Options. + * + * Copied from {@link BitmapFactory#setDensityFromOptions(Bitmap, Options)}. + */ + @LayoutlibDelegate + /*package*/ static void setDensityFromOptions(Bitmap outputBitmap, Options opts) { + if (outputBitmap == null || opts == null) return; + + final int density = opts.inDensity; + if (density != 0) { + outputBitmap.setDensity(density); + final int targetDensity = opts.inTargetDensity; + if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) { + return; + } + + // --- Change from original implementation begins --- + // LayoutLib doesn't scale the nine patch when decoding it. Hence, don't change the + // density of the source bitmap in case of ninepatch. + + if (opts.inScaled) { + // --- Change from original implementation ends. --- + outputBitmap.setDensity(targetDensity); + } + } else if (opts.inBitmap != null) { + // bitmap was reused, ensure density is reset + outputBitmap.setDensity(Bitmap.getDefaultDensity()); + } + } } diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png Binary files differindex 2b86bfba54cc..d8ead233b4ec 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png Binary files differnew file mode 100644 index 000000000000..65d1dc5b1edb --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java index 2dca07cc4faf..dea86bfb5a38 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java @@ -305,6 +305,11 @@ public class Main { renderAndVerify("array_check.xml", "array_check.png"); } + @Test + public void testAllWidgetsTablet() throws ClassNotFoundException { + renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012); + } + @AfterClass public static void tearDown() { sLayoutLibLog = null; @@ -423,6 +428,16 @@ public class Main { */ private void renderAndVerify(String layoutFileName, String goldenFileName) throws ClassNotFoundException { + renderAndVerify(layoutFileName, goldenFileName, ConfigGenerator.NEXUS_5); + } + + /** + * Create a new rendering session and test that rendering given layout on given device + * doesn't throw any exceptions and matches the provided image. + */ + private void renderAndVerify(String layoutFileName, String goldenFileName, + ConfigGenerator deviceConfig) + throws ClassNotFoundException { // Create the layout pull parser. LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutFileName); // Create LayoutLibCallback. @@ -430,7 +445,7 @@ public class Main { layoutLibCallback.initResources(); // TODO: Set up action bar handler properly to test menu rendering. // Create session params. - SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, + SessionParams params = getSessionParams(parser, deviceConfig, layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22); renderAndVerify(params, goldenFileName); } diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java index 8e0cec6b550f..34fc726352cd 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java @@ -126,6 +126,21 @@ public class ConfigGenerator { .setSoftButtons(true) .setNavigation(Navigation.NONAV); + public static final ConfigGenerator NEXUS_7_2012 = new ConfigGenerator() + .setScreenHeight(1280) + .setScreenWidth(800) + .setXdpi(195) + .setYdpi(200) + .setOrientation(ScreenOrientation.PORTRAIT) + .setDensity(Density.TV) + .setRatio(ScreenRatio.NOTLONG) + .setSize(ScreenSize.LARGE) + .setKeyboard(Keyboard.NOKEY) + .setTouchScreen(TouchScreen.FINGER) + .setKeyboardState(KeyboardState.SOFT) + .setSoftButtons(true) + .setNavigation(Navigation.NONAV); + private static final String TAG_ATTR = "attr"; private static final String TAG_ENUM = "enum"; private static final String TAG_FLAG = "flag"; diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 3ca7590b2e83..6e6ad8f11019 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -166,6 +166,7 @@ public final class CreateInfo implements ICreateInfo { "android.content.res.TypedArray#getValueAt", "android.content.res.TypedArray#obtain", "android.graphics.BitmapFactory#finishDecode", + "android.graphics.BitmapFactory#setDensityFromOptions", "android.graphics.drawable.GradientDrawable#buildRing", "android.graphics.Typeface#getSystemFontConfigLocation", "android.os.Handler#sendMessageAtTime", |