diff options
553 files changed, 14495 insertions, 6287 deletions
diff --git a/Android.mk b/Android.mk index c3e679b63e5c..6ec434cfbf54 100644 --- a/Android.mk +++ b/Android.mk @@ -520,7 +520,7 @@ aidl_files := \ frameworks/base/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl \ frameworks/base/wifi/java/android/net/wifi/WpsInfo.aidl \ frameworks/base/wifi/java/android/net/wifi/ScanResult.aidl \ - frameworks/base/wifi/java/android/net/wifi/ScanInfo.aidl \ + frameworks/base/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl \ frameworks/base/wifi/java/android/net/wifi/WifiEnterpriseConfig.aidl \ frameworks/base/wifi/java/android/net/wifi/WifiConfiguration.aidl \ frameworks/base/wifi/java/android/net/wifi/WifiInfo.aidl \ @@ -1193,6 +1193,11 @@ LOCAL_MODULE := ext LOCAL_DX_FLAGS := --core-library +ifneq ($(INCREMENTAL_BUILDS),) + LOCAL_PROGUARD_ENABLED := disabled + LOCAL_JACK_ENABLED := incremental +endif + include $(BUILD_JAVA_LIBRARY) diff --git a/api/current.txt b/api/current.txt index 41b2d3ebc834..dd9b5a1ef284 100644 --- a/api/current.txt +++ b/api/current.txt @@ -198,6 +198,7 @@ package android { public static final class R.attr { ctor public R.attr(); + field public static final int abiOverride = 16844054; // 0x1010516 field public static final int absListViewStyle = 16842858; // 0x101006a field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 @@ -305,6 +306,7 @@ package android { field public static final int baselineAlignBottom = 16843042; // 0x1010122 field public static final int baselineAligned = 16843046; // 0x1010126 field public static final int baselineAlignedChildIndex = 16843047; // 0x1010127 + field public static final int bitmap = 16844055; // 0x1010517 field public static final int borderlessButtonStyle = 16843563; // 0x101032b field public static final int bottom = 16843184; // 0x10101b0 field public static final int bottomBright = 16842957; // 0x10100cd @@ -646,6 +648,8 @@ package android { field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353 field public static final int horizontalSpacing = 16843028; // 0x1010114 field public static final int host = 16842792; // 0x1010028 + field public static final int hotSpotX = 16844056; // 0x1010518 + field public static final int hotSpotY = 16844057; // 0x1010519 field public static final int hyphenationFrequency = 16843998; // 0x10104de field public static final int icon = 16842754; // 0x1010002 field public static final int iconPreview = 16843337; // 0x1010249 @@ -6319,6 +6323,22 @@ package android.app.usage { field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR; } + public class DataUsagePolicy { + field public final int networkType; + field public final java.lang.String[] subscriberIds; + field public final long thresholdInBytes; + field public final int[] uids; + } + + public static class DataUsagePolicy.Builder { + ctor public DataUsagePolicy.Builder(); + method public android.app.usage.DataUsagePolicy.Builder addSubscriberId(java.lang.String); + method public android.app.usage.DataUsagePolicy.Builder addUid(int); + method public android.app.usage.DataUsagePolicy build(); + method public android.app.usage.DataUsagePolicy.Builder setNetworkType(int); + method public android.app.usage.DataUsagePolicy.Builder setThreshold(long); + } + public final class NetworkStats implements java.lang.AutoCloseable { method public void close(); method public boolean getNextBucket(android.app.usage.NetworkStats.Bucket); @@ -6359,6 +6379,14 @@ package android.app.usage { method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException; method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException; method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException; + method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback); + method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback, android.os.Handler); + method public void unregisterDataUsageCallback(android.app.usage.NetworkStatsManager.DataUsageCallback); + } + + public static class NetworkStatsManager.DataUsageCallback { + ctor public NetworkStatsManager.DataUsageCallback(); + method public void onLimitReached(); } public final class UsageEvents implements android.os.Parcelable { @@ -8060,6 +8088,7 @@ package android.content { field public static final int BIND_ALLOW_OOM_MANAGEMENT = 16; // 0x10 field public static final int BIND_AUTO_CREATE = 1; // 0x1 field public static final int BIND_DEBUG_UNBIND = 2; // 0x2 + field public static final int BIND_EXTERNAL_SERVICE = -2147483648; // 0x80000000 field public static final int BIND_IMPORTANT = 64; // 0x40 field public static final int BIND_NOT_FOREGROUND = 4; // 0x4 field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20 @@ -9915,6 +9944,7 @@ package android.content.pm { method public int describeContents(); method public void dump(android.util.Printer, java.lang.String); field public static final android.os.Parcelable.Creator<android.content.pm.ServiceInfo> CREATOR; + field public static final int FLAG_EXTERNAL_SERVICE = 4; // 0x4 field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2 field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000 field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1 @@ -23444,6 +23474,12 @@ package android.net { method public int getUid(); } + public class DataUsageRequest implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.DataUsageRequest> CREATOR; + } + public class DhcpInfo implements android.os.Parcelable { ctor public DhcpInfo(); method public int describeContents(); @@ -24310,22 +24346,6 @@ package android.net.sip { package android.net.wifi { - public class ScanInfo implements android.os.Parcelable { - ctor public ScanInfo(android.net.wifi.ScanResult); - ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int); - method public int describeContents(); - method public long getBssid(); - method public byte[] getIconData(); - method public java.lang.String getIconType(); - method public java.lang.String getName(); - method public int getOsuIdentity(); - method public int getRssi(); - method public android.net.wifi.ScanResult getScanResult(); - method public java.lang.String getServiceDescription(); - method public java.lang.String getSsid(); - method public void writeToParcel(android.os.Parcel, int); - } - public class ScanResult implements android.os.Parcelable { method public int describeContents(); method public boolean is80211mcResponder(); @@ -24486,6 +24506,7 @@ package android.net.wifi { field public static final int SIM = 4; // 0x4 field public static final int TLS = 1; // 0x1 field public static final int TTLS = 2; // 0x2 + field public static final int UNAUTH_TLS = 7; // 0x7 } public static final class WifiEnterpriseConfig.Phase2 { @@ -24528,7 +24549,6 @@ package android.net.wifi { method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks(); method public android.net.wifi.WifiInfo getConnectionInfo(); method public android.net.DhcpInfo getDhcpInfo(); - method public java.util.List<android.net.wifi.ScanInfo> getScanInfos(); method public java.util.List<android.net.wifi.ScanResult> getScanResults(); method public int getWifiState(); method public boolean is5GHzBandSupported(); @@ -24544,7 +24564,6 @@ package android.net.wifi { method public boolean reconnect(); method public boolean removeNetwork(int); method public boolean saveConfiguration(); - method public void setOsuSelection(int); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); method public boolean setWifiEnabled(boolean); @@ -32093,6 +32112,7 @@ package android.provider { field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS"; field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS"; field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS"; + field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS"; field public static final java.lang.String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"; field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS"; field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS"; @@ -34349,6 +34369,9 @@ package android.service.media { ctor public MediaBrowserService.BrowserRoot(java.lang.String, android.os.Bundle); method public android.os.Bundle getExtras(); method public java.lang.String getRootId(); + field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE"; + field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT"; + field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED"; } public class MediaBrowserService.Result { @@ -36334,6 +36357,7 @@ package android.telecom { method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle); method public boolean isInCall(); method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String); + method public void launchManageBlockedNumbersActivity(); method public void placeCall(android.net.Uri, android.os.Bundle); method public void registerPhoneAccount(android.telecom.PhoneAccount); method public void showInCallScreen(boolean); @@ -40049,7 +40073,6 @@ package android.util { method public static android.util.LocaleList getDefault(); 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); @@ -50187,13 +50210,16 @@ package java.lang { method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException; method public A getAnnotation(java.lang.Class<A>); method public java.lang.annotation.Annotation[] getAnnotations(); + method public T[] getAnnotationsByType(java.lang.Class<T>); method public java.lang.String getCanonicalName(); method public java.lang.ClassLoader getClassLoader(); method public java.lang.Class<?>[] getClasses(); method public java.lang.Class<?> getComponentType(); method public java.lang.reflect.Constructor<T> getConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; method public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException; + method public T getDeclaredAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public java.lang.Class<?>[] getDeclaredClasses(); method public java.lang.reflect.Constructor<T> getDeclaredConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; method public java.lang.reflect.Constructor<?>[] getDeclaredConstructors() throws java.lang.SecurityException; @@ -50724,7 +50750,10 @@ package java.lang { public class Package implements java.lang.reflect.AnnotatedElement { method public A getAnnotation(java.lang.Class<A>); method public java.lang.annotation.Annotation[] getAnnotations(); + method public T[] getAnnotationsByType(java.lang.Class<T>); + method public java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public java.lang.String getImplementationTitle(); method public java.lang.String getImplementationVendor(); method public java.lang.String getImplementationVersion(); @@ -51418,7 +51447,10 @@ package java.lang.reflect { ctor protected AccessibleObject(); method public T getAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getAnnotations(); + method public T[] getAnnotationsByType(java.lang.Class<T>); + method public java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public boolean isAccessible(); method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public static void setAccessible(java.lang.reflect.AccessibleObject[], boolean) throws java.lang.SecurityException; @@ -51428,7 +51460,10 @@ package java.lang.reflect { public abstract interface AnnotatedElement { method public abstract T getAnnotation(java.lang.Class<T>); method public abstract java.lang.annotation.Annotation[] getAnnotations(); + method public abstract T[] getAnnotationsByType(java.lang.Class<T>); + method public abstract java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>); method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public abstract T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public abstract boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); } diff --git a/api/system-current.txt b/api/system-current.txt index 10d1b04c4fde..ef4841e8fb4e 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -91,6 +91,7 @@ package android { field public static final java.lang.String DEVICE_POWER = "android.permission.DEVICE_POWER"; field public static final java.lang.String DIAGNOSTIC = "android.permission.DIAGNOSTIC"; field public static final java.lang.String DISABLE_KEYGUARD = "android.permission.DISABLE_KEYGUARD"; + field public static final java.lang.String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE"; field public static final java.lang.String DUMP = "android.permission.DUMP"; field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR"; field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST"; @@ -401,6 +402,7 @@ package android { field public static final int baselineAlignBottom = 16843042; // 0x1010122 field public static final int baselineAligned = 16843046; // 0x1010126 field public static final int baselineAlignedChildIndex = 16843047; // 0x1010127 + field public static final int bitmap = 16844055; // 0x1010517 field public static final int borderlessButtonStyle = 16843563; // 0x101032b field public static final int bottom = 16843184; // 0x10101b0 field public static final int bottomBright = 16842957; // 0x10100cd @@ -742,6 +744,8 @@ package android { field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353 field public static final int horizontalSpacing = 16843028; // 0x1010114 field public static final int host = 16842792; // 0x1010028 + field public static final int hotSpotX = 16844056; // 0x1010518 + field public static final int hotSpotY = 16844057; // 0x1010519 field public static final int hyphenationFrequency = 16843998; // 0x10104de field public static final int icon = 16842754; // 0x1010002 field public static final int iconPreview = 16843337; // 0x1010249 @@ -6100,6 +6104,7 @@ package android.app.admin { field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED"; field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED"; field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE"; + field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE"; field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE"; field public static final java.lang.String ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = "android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD"; field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD"; @@ -6577,6 +6582,22 @@ package android.app.usage { field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR; } + public class DataUsagePolicy { + field public final int networkType; + field public final java.lang.String[] subscriberIds; + field public final long thresholdInBytes; + field public final int[] uids; + } + + public static class DataUsagePolicy.Builder { + ctor public DataUsagePolicy.Builder(); + method public android.app.usage.DataUsagePolicy.Builder addSubscriberId(java.lang.String); + method public android.app.usage.DataUsagePolicy.Builder addUid(int); + method public android.app.usage.DataUsagePolicy build(); + method public android.app.usage.DataUsagePolicy.Builder setNetworkType(int); + method public android.app.usage.DataUsagePolicy.Builder setThreshold(long); + } + public final class NetworkStats implements java.lang.AutoCloseable { method public void close(); method public boolean getNextBucket(android.app.usage.NetworkStats.Bucket); @@ -6617,6 +6638,14 @@ package android.app.usage { method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException; method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException; method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException; + method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback); + method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback, android.os.Handler); + method public void unregisterDataUsageCallback(android.app.usage.NetworkStatsManager.DataUsageCallback); + } + + public static class NetworkStatsManager.DataUsageCallback { + ctor public NetworkStatsManager.DataUsageCallback(); + method public void onLimitReached(); } public final class UsageEvents implements android.os.Parcelable { @@ -10317,6 +10346,7 @@ package android.content.pm { method public int describeContents(); method public void dump(android.util.Printer, java.lang.String); field public static final android.os.Parcelable.Creator<android.content.pm.ServiceInfo> CREATOR; + field public static final int FLAG_EXTERNAL_SERVICE = 4; // 0x4 field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2 field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000 field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1 @@ -25250,6 +25280,12 @@ package android.net { method public int getUid(); } + public class DataUsageRequest implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.DataUsageRequest> CREATOR; + } + public class DhcpInfo implements android.os.Parcelable { ctor public DhcpInfo(); method public int describeContents(); @@ -26359,22 +26395,6 @@ package android.net.wifi { field public byte id; } - public class ScanInfo implements android.os.Parcelable { - ctor public ScanInfo(android.net.wifi.ScanResult); - ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int); - method public int describeContents(); - method public long getBssid(); - method public byte[] getIconData(); - method public java.lang.String getIconType(); - method public java.lang.String getName(); - method public int getOsuIdentity(); - method public int getRssi(); - method public android.net.wifi.ScanResult getScanResult(); - method public java.lang.String getServiceDescription(); - method public java.lang.String getSsid(); - method public void writeToParcel(android.os.Parcel, int); - } - public class ScanResult implements android.os.Parcelable { method public int describeContents(); method public boolean is80211mcResponder(); @@ -26558,6 +26578,7 @@ package android.net.wifi { field public static final int SIM = 4; // 0x4 field public static final int TLS = 1; // 0x1 field public static final int TTLS = 2; // 0x2 + field public static final int UNAUTH_TLS = 7; // 0x7 } public static final class WifiEnterpriseConfig.Phase2 { @@ -26603,7 +26624,6 @@ package android.net.wifi { method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics(); method public android.net.DhcpInfo getDhcpInfo(); method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks(); - method public java.util.List<android.net.wifi.ScanInfo> getScanInfos(); method public java.util.List<android.net.wifi.ScanResult> getScanResults(); method public android.net.wifi.WifiConfiguration getWifiApConfiguration(); method public int getWifiApState(); @@ -26626,7 +26646,6 @@ package android.net.wifi { method public boolean reconnect(); method public boolean removeNetwork(int); method public boolean saveConfiguration(); - method public void setOsuSelection(int); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration); @@ -34502,6 +34521,7 @@ package android.provider { field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS"; field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS"; field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS"; + field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS"; field public static final java.lang.String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"; field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS"; field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS"; @@ -36759,6 +36779,9 @@ package android.service.media { ctor public MediaBrowserService.BrowserRoot(java.lang.String, android.os.Bundle); method public android.os.Bundle getExtras(); method public java.lang.String getRootId(); + field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE"; + field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT"; + field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED"; } public class MediaBrowserService.Result { @@ -38911,6 +38934,7 @@ package android.telecom { method public boolean isRinging(); method public boolean isTtySupported(); method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String); + method public void launchManageBlockedNumbersActivity(); method public void placeCall(android.net.Uri, android.os.Bundle); method public void registerPhoneAccount(android.telecom.PhoneAccount); method public void showInCallScreen(boolean); @@ -42697,7 +42721,6 @@ package android.util { method public static android.util.LocaleList getDefault(); 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); @@ -53171,13 +53194,16 @@ package java.lang { method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException; method public A getAnnotation(java.lang.Class<A>); method public java.lang.annotation.Annotation[] getAnnotations(); + method public T[] getAnnotationsByType(java.lang.Class<T>); method public java.lang.String getCanonicalName(); method public java.lang.ClassLoader getClassLoader(); method public java.lang.Class<?>[] getClasses(); method public java.lang.Class<?> getComponentType(); method public java.lang.reflect.Constructor<T> getConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; method public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException; + method public T getDeclaredAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public java.lang.Class<?>[] getDeclaredClasses(); method public java.lang.reflect.Constructor<T> getDeclaredConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; method public java.lang.reflect.Constructor<?>[] getDeclaredConstructors() throws java.lang.SecurityException; @@ -53708,7 +53734,10 @@ package java.lang { public class Package implements java.lang.reflect.AnnotatedElement { method public A getAnnotation(java.lang.Class<A>); method public java.lang.annotation.Annotation[] getAnnotations(); + method public T[] getAnnotationsByType(java.lang.Class<T>); + method public java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public java.lang.String getImplementationTitle(); method public java.lang.String getImplementationVendor(); method public java.lang.String getImplementationVersion(); @@ -54402,7 +54431,10 @@ package java.lang.reflect { ctor protected AccessibleObject(); method public T getAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getAnnotations(); + method public T[] getAnnotationsByType(java.lang.Class<T>); + method public java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public boolean isAccessible(); method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public static void setAccessible(java.lang.reflect.AccessibleObject[], boolean) throws java.lang.SecurityException; @@ -54412,7 +54444,10 @@ package java.lang.reflect { public abstract interface AnnotatedElement { method public abstract T getAnnotation(java.lang.Class<T>); method public abstract java.lang.annotation.Annotation[] getAnnotations(); + method public abstract T[] getAnnotationsByType(java.lang.Class<T>); + method public abstract java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>); method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public abstract T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public abstract boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); } diff --git a/api/test-current.txt b/api/test-current.txt index 42bad76ed3ee..80d82c3d84ff 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -198,6 +198,7 @@ package android { public static final class R.attr { ctor public R.attr(); + field public static final int abiOverride = 16844054; // 0x1010516 field public static final int absListViewStyle = 16842858; // 0x101006a field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 @@ -305,6 +306,7 @@ package android { field public static final int baselineAlignBottom = 16843042; // 0x1010122 field public static final int baselineAligned = 16843046; // 0x1010126 field public static final int baselineAlignedChildIndex = 16843047; // 0x1010127 + field public static final int bitmap = 16844055; // 0x1010517 field public static final int borderlessButtonStyle = 16843563; // 0x101032b field public static final int bottom = 16843184; // 0x10101b0 field public static final int bottomBright = 16842957; // 0x10100cd @@ -646,6 +648,8 @@ package android { field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353 field public static final int horizontalSpacing = 16843028; // 0x1010114 field public static final int host = 16842792; // 0x1010028 + field public static final int hotSpotX = 16844056; // 0x1010518 + field public static final int hotSpotY = 16844057; // 0x1010519 field public static final int hyphenationFrequency = 16843998; // 0x10104de field public static final int icon = 16842754; // 0x1010002 field public static final int iconPreview = 16843337; // 0x1010249 @@ -6321,6 +6325,22 @@ package android.app.usage { field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR; } + public class DataUsagePolicy { + field public final int networkType; + field public final java.lang.String[] subscriberIds; + field public final long thresholdInBytes; + field public final int[] uids; + } + + public static class DataUsagePolicy.Builder { + ctor public DataUsagePolicy.Builder(); + method public android.app.usage.DataUsagePolicy.Builder addSubscriberId(java.lang.String); + method public android.app.usage.DataUsagePolicy.Builder addUid(int); + method public android.app.usage.DataUsagePolicy build(); + method public android.app.usage.DataUsagePolicy.Builder setNetworkType(int); + method public android.app.usage.DataUsagePolicy.Builder setThreshold(long); + } + public final class NetworkStats implements java.lang.AutoCloseable { method public void close(); method public boolean getNextBucket(android.app.usage.NetworkStats.Bucket); @@ -6361,6 +6381,14 @@ package android.app.usage { method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException; method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException; method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long, boolean) throws android.os.RemoteException, java.lang.SecurityException; + method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback); + method public void registerDataUsageCallback(android.app.usage.DataUsagePolicy, android.app.usage.NetworkStatsManager.DataUsageCallback, android.os.Handler); + method public void unregisterDataUsageCallback(android.app.usage.NetworkStatsManager.DataUsageCallback); + } + + public static class NetworkStatsManager.DataUsageCallback { + ctor public NetworkStatsManager.DataUsageCallback(); + method public void onLimitReached(); } public final class UsageEvents implements android.os.Parcelable { @@ -8064,6 +8092,7 @@ package android.content { field public static final int BIND_ALLOW_OOM_MANAGEMENT = 16; // 0x10 field public static final int BIND_AUTO_CREATE = 1; // 0x1 field public static final int BIND_DEBUG_UNBIND = 2; // 0x2 + field public static final int BIND_EXTERNAL_SERVICE = -2147483648; // 0x80000000 field public static final int BIND_IMPORTANT = 64; // 0x40 field public static final int BIND_NOT_FOREGROUND = 4; // 0x4 field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20 @@ -9923,6 +9952,7 @@ package android.content.pm { method public int describeContents(); method public void dump(android.util.Printer, java.lang.String); field public static final android.os.Parcelable.Creator<android.content.pm.ServiceInfo> CREATOR; + field public static final int FLAG_EXTERNAL_SERVICE = 4; // 0x4 field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2 field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000 field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1 @@ -23453,6 +23483,12 @@ package android.net { method public int getUid(); } + public class DataUsageRequest implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.DataUsageRequest> CREATOR; + } + public class DhcpInfo implements android.os.Parcelable { ctor public DhcpInfo(); method public int describeContents(); @@ -24319,22 +24355,6 @@ package android.net.sip { package android.net.wifi { - public class ScanInfo implements android.os.Parcelable { - ctor public ScanInfo(android.net.wifi.ScanResult); - ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int); - method public int describeContents(); - method public long getBssid(); - method public byte[] getIconData(); - method public java.lang.String getIconType(); - method public java.lang.String getName(); - method public int getOsuIdentity(); - method public int getRssi(); - method public android.net.wifi.ScanResult getScanResult(); - method public java.lang.String getServiceDescription(); - method public java.lang.String getSsid(); - method public void writeToParcel(android.os.Parcel, int); - } - public class ScanResult implements android.os.Parcelable { method public int describeContents(); method public boolean is80211mcResponder(); @@ -24495,6 +24515,7 @@ package android.net.wifi { field public static final int SIM = 4; // 0x4 field public static final int TLS = 1; // 0x1 field public static final int TTLS = 2; // 0x2 + field public static final int UNAUTH_TLS = 7; // 0x7 } public static final class WifiEnterpriseConfig.Phase2 { @@ -24537,7 +24558,6 @@ package android.net.wifi { method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks(); method public android.net.wifi.WifiInfo getConnectionInfo(); method public android.net.DhcpInfo getDhcpInfo(); - method public java.util.List<android.net.wifi.ScanInfo> getScanInfos(); method public java.util.List<android.net.wifi.ScanResult> getScanResults(); method public int getWifiState(); method public boolean is5GHzBandSupported(); @@ -24553,7 +24573,6 @@ package android.net.wifi { method public boolean reconnect(); method public boolean removeNetwork(int); method public boolean saveConfiguration(); - method public void setOsuSelection(int); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); method public boolean setWifiEnabled(boolean); @@ -32106,6 +32125,7 @@ package android.provider { field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS"; field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS"; field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS"; + field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS"; field public static final java.lang.String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"; field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS"; field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS"; @@ -34364,6 +34384,9 @@ package android.service.media { ctor public MediaBrowserService.BrowserRoot(java.lang.String, android.os.Bundle); method public android.os.Bundle getExtras(); method public java.lang.String getRootId(); + field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE"; + field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT"; + field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED"; } public class MediaBrowserService.Result { @@ -36349,6 +36372,7 @@ package android.telecom { method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle); method public boolean isInCall(); method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String); + method public void launchManageBlockedNumbersActivity(); method public void placeCall(android.net.Uri, android.os.Bundle); method public void registerPhoneAccount(android.telecom.PhoneAccount); method public void showInCallScreen(boolean); @@ -40066,7 +40090,6 @@ package android.util { method public static android.util.LocaleList getDefault(); 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); @@ -50204,13 +50227,16 @@ package java.lang { method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException; method public A getAnnotation(java.lang.Class<A>); method public java.lang.annotation.Annotation[] getAnnotations(); + method public T[] getAnnotationsByType(java.lang.Class<T>); method public java.lang.String getCanonicalName(); method public java.lang.ClassLoader getClassLoader(); method public java.lang.Class<?>[] getClasses(); method public java.lang.Class<?> getComponentType(); method public java.lang.reflect.Constructor<T> getConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; method public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException; + method public T getDeclaredAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public java.lang.Class<?>[] getDeclaredClasses(); method public java.lang.reflect.Constructor<T> getDeclaredConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; method public java.lang.reflect.Constructor<?>[] getDeclaredConstructors() throws java.lang.SecurityException; @@ -50741,7 +50767,10 @@ package java.lang { public class Package implements java.lang.reflect.AnnotatedElement { method public A getAnnotation(java.lang.Class<A>); method public java.lang.annotation.Annotation[] getAnnotations(); + method public T[] getAnnotationsByType(java.lang.Class<T>); + method public java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public java.lang.String getImplementationTitle(); method public java.lang.String getImplementationVendor(); method public java.lang.String getImplementationVersion(); @@ -51435,7 +51464,10 @@ package java.lang.reflect { ctor protected AccessibleObject(); method public T getAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getAnnotations(); + method public T[] getAnnotationsByType(java.lang.Class<T>); + method public java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>); method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public boolean isAccessible(); method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public static void setAccessible(java.lang.reflect.AccessibleObject[], boolean) throws java.lang.SecurityException; @@ -51445,7 +51477,10 @@ package java.lang.reflect { public abstract interface AnnotatedElement { method public abstract T getAnnotation(java.lang.Class<T>); method public abstract java.lang.annotation.Annotation[] getAnnotations(); + method public abstract T[] getAnnotationsByType(java.lang.Class<T>); + method public abstract java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>); method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method public abstract T[] getDeclaredAnnotationsByType(java.lang.Class<T>); method public abstract boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); } diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 9d81c438360f..a74a1ca7cbe6 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -1774,18 +1774,33 @@ public class Am extends BaseCommand { System.err.println("Error: invalid input bounds"); return; } - resizeStack(stackId, bounds, 0, false); + resizeStack(stackId, bounds, 0); } private void runStackResizeAnimated() throws Exception { String stackIdStr = nextArgRequired(); int stackId = Integer.valueOf(stackIdStr); - final Rect bounds = getBounds(); - if (bounds == null) { - System.err.println("Error: invalid input bounds"); - return; + final Rect bounds; + if ("null".equals(mArgs.peekNextArg())) { + bounds = null; + } else { + bounds = getBounds(); + if (bounds == null) { + System.err.println("Error: invalid input bounds"); + return; + } + } + resizeStackUnchecked(stackId, bounds, 0, true); + } + + private void resizeStackUnchecked(int stackId, Rect bounds, int delayMs, boolean animate) { + try { + mAm.resizeStack(stackId, bounds, false, false, animate); + Thread.sleep(delayMs); + } catch (RemoteException e) { + showError("Error: resizing stack " + e); + } catch (InterruptedException e) { } - resizeStack(stackId, bounds, 0, true); } private void runStackResizeDocked() throws Exception { @@ -1802,20 +1817,13 @@ public class Am extends BaseCommand { } } - private void resizeStack(int stackId, Rect bounds, int delayMs, boolean animate) + private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception { if (bounds == null) { showError("Error: invalid input bounds"); return; } - - try { - mAm.resizeStack(stackId, bounds, false, false, animate); - Thread.sleep(delayMs); - } catch (RemoteException e) { - showError("Error: resizing stack " + e); - } catch (InterruptedException e) { - } + resizeStackUnchecked(stackId, bounds, delayMs, false); } private void runStackPositionTask() throws Exception { @@ -1924,7 +1932,7 @@ public class Am extends BaseCommand { maxChange = Math.min(stepSize, currentPoint - minPoint); currentPoint -= maxChange; setBoundsSide(bounds, side, currentPoint); - resizeStack(DOCKED_STACK_ID, bounds, delayMs, false); + resizeStack(DOCKED_STACK_ID, bounds, delayMs); } System.out.println("Growing docked stack side=" + side); @@ -1932,7 +1940,7 @@ public class Am extends BaseCommand { maxChange = Math.min(stepSize, maxPoint - currentPoint); currentPoint += maxChange; setBoundsSide(bounds, side, currentPoint); - resizeStack(DOCKED_STACK_ID, bounds, delayMs, false); + resizeStack(DOCKED_STACK_ID, bounds, delayMs); } System.out.println("Back to Original size side=" + side); @@ -1940,7 +1948,7 @@ public class Am extends BaseCommand { maxChange = Math.min(stepSize, currentPoint - startPoint); currentPoint -= maxChange; setBoundsSide(bounds, side, currentPoint); - resizeStack(DOCKED_STACK_ID, bounds, delayMs, false); + resizeStack(DOCKED_STACK_ID, bounds, delayMs); } } diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 980329fe31c8..1ab55dd7c1d9 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -1030,20 +1030,6 @@ public final class AnimatorSet extends Animator { } } - /** - * @hide - * TODO: For animatorSet defined in XML, we can use a flag to indicate what the play order - * if defined (i.e. sequential or together), then we can use the flag instead of calculate - * dynamically. - * @return whether all the animators in the set are supposed to play together - */ - public boolean shouldPlayTogether() { - updateAnimatorsDuration(); - createDependencyGraph(); - // All the child nodes are set out to play right after the delay animation - return mRootNode.mChildNodes.size() == mNodes.size() - 1; - } - @Override public long getTotalDuration() { updateAnimatorsDuration(); diff --git a/core/java/android/animation/PathKeyframes.java b/core/java/android/animation/PathKeyframes.java index 8230ac5bbfc5..2a47b68a41b0 100644 --- a/core/java/android/animation/PathKeyframes.java +++ b/core/java/android/animation/PathKeyframes.java @@ -231,7 +231,7 @@ class PathKeyframes implements Keyframes { } } - abstract static class IntKeyframesBase extends SimpleKeyframes implements IntKeyframes { + private abstract static class IntKeyframesBase extends SimpleKeyframes implements IntKeyframes { @Override public Class getType() { return Integer.class; @@ -243,7 +243,7 @@ class PathKeyframes implements Keyframes { } } - abstract static class FloatKeyframesBase extends SimpleKeyframes + private abstract static class FloatKeyframesBase extends SimpleKeyframes implements FloatKeyframes { @Override public Class getType() { diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index 6ba5b968dfe7..e993cca9e325 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -21,7 +21,6 @@ import android.graphics.PointF; import android.util.FloatProperty; import android.util.IntProperty; import android.util.Log; -import android.util.PathParser; import android.util.Property; import java.lang.reflect.InvocationTargetException; @@ -1047,43 +1046,6 @@ public class PropertyValuesHolder implements Cloneable { return mAnimatedValue; } - /** - * PropertyValuesHolder is Animators use to hold internal animation related data. - * Therefore, in order to replicate the animation behavior, we need to get data out of - * PropertyValuesHolder. - * @hide - */ - public void getPropertyValues(PropertyValues values) { - init(); - values.propertyName = mPropertyName; - values.type = mValueType; - values.startValue = mKeyframes.getValue(0); - if (values.startValue instanceof PathParser.PathData) { - // PathData evaluator returns the same mutable PathData object when query fraction, - // so we have to make a copy here. - values.startValue = new PathParser.PathData((PathParser.PathData) values.startValue); - } - values.endValue = mKeyframes.getValue(1); - if (values.endValue instanceof PathParser.PathData) { - // PathData evaluator returns the same mutable PathData object when query fraction, - // so we have to make a copy here. - values.endValue = new PathParser.PathData((PathParser.PathData) values.endValue); - } - // TODO: We need a better way to get data out of keyframes. - if (mKeyframes instanceof PathKeyframes.FloatKeyframesBase - || mKeyframes instanceof PathKeyframes.IntKeyframesBase) { - // property values will animate based on external data source (e.g. Path) - values.dataSource = new PropertyValues.DataSource() { - @Override - public Object getValueAtFraction(float fraction) { - return mKeyframes.getValue(fraction); - } - }; - } else { - values.dataSource = null; - } - } - @Override public String toString() { return mPropertyName + ": " + mKeyframes.toString(); @@ -1639,24 +1601,6 @@ public class PropertyValuesHolder implements Cloneable { } }; - /** - * @hide - */ - public static class PropertyValues { - public String propertyName; - public Class type; - public Object startValue; - public Object endValue; - public DataSource dataSource = null; - public interface DataSource { - Object getValueAtFraction(float fraction); - } - public String toString() { - return ("property name: " + propertyName + ", type: " + type + ", startValue: " - + startValue.toString() + ", endValue: " + endValue.toString()); - } - } - native static private long nGetIntMethod(Class targetClass, String methodName); native static private long nGetFloatMethod(Class targetClass, String methodName); native static private long nGetMultipleIntMethod(Class targetClass, String methodName, diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 805b2034ff05..6424520df3ec 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4822,14 +4822,12 @@ public final class ActivityThread { } private void updateDefaultDensity() { - if (mCurDefaultDisplayDpi != Configuration.DENSITY_DPI_UNDEFINED - && mCurDefaultDisplayDpi != DisplayMetrics.DENSITY_DEVICE - && !mDensityCompatMode) { - Slog.i(TAG, "Switching default density from " - + DisplayMetrics.DENSITY_DEVICE + " to " - + mCurDefaultDisplayDpi); - DisplayMetrics.DENSITY_DEVICE = mCurDefaultDisplayDpi; - Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT); + final int densityDpi = mCurDefaultDisplayDpi; + if (!mDensityCompatMode + && densityDpi != Configuration.DENSITY_DPI_UNDEFINED + && densityDpi != DisplayMetrics.DENSITY_DEVICE) { + DisplayMetrics.DENSITY_DEVICE = densityDpi; + Bitmap.setDefaultDensity(densityDpi); } } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 1e22bef63d8c..da52c1e5ba1d 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -382,6 +382,13 @@ public final class LoadedApk { libraryPermittedPath += File.pathSeparator + System.getProperty("java.library.path"); } + // DO NOT SHIP: this is a workaround for apps loading native libraries + // provided by 3rd party apps using absolute path instead of corresponding + // classloader; see http://b/26954419 for example. + if (mApplicationInfo.targetSdkVersion <= 23) { + libraryPermittedPath += File.pathSeparator + "/data/app"; + } + // ----------------------------------------------------------------------------- final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 9bad2f9dc238..02eb115175fd 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -241,6 +241,48 @@ public class DevicePolicyManager { /** * Activity action: Starts the provisioning flow which sets up a managed device. + * + * <p>During device owner provisioning, a device admin app is downloaded and set as the owner of + * the device. A device owner has full control over the device. The device owner can not be + * modified by the user and the only way of resetting the device is via factory reset. + * + * <p>A typical use case would be a device that is owned by a company, but used by either an + * employee or client. + * + * <p>The provisioning message should be sent to an unprovisioned device. + * + * <p>Unlike {@link #ACTION_PROVISION_MANAGED_DEVICE}, the provisioning message can only be sent + * by a privileged app with the permission + * {@link android.Manifest.permission#DISPATCH_PROVISIONING_MESSAGE}. + * + * <p>The provisioning intent contains the following properties: + * <ul> + * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</li> + * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME} (convert to String), optional</li> + * <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_LOCALE}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_WIFI_SSID}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_WIFI_HIDDEN} (convert to String), optional</li> + * <li>{@link #EXTRA_PROVISIONING_WIFI_SECURITY_TYPE}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_WIFI_PASSWORD}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_HOST}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_PORT} (convert to String), optional</li> + * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_BYPASS}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li></ul> + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + @SystemApi + public static final String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = + "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE"; + + /** + * Activity action: Starts the provisioning flow which sets up a managed device. * Must be started with {@link android.app.Activity#startActivityForResult(Intent, int)}. * * <p>NOTE: This is only supported on split system user devices, and puts the device into a @@ -4067,6 +4109,29 @@ public class DevicePolicyManager { } /** + * Called by the system to check if a specific accessibility service is disabled by admin. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param packageName Accessibility service package name that needs to be checked. + * @param userHandle user id the admin is running as. + * @return true if the accessibility service is permitted, otherwise false. + * + * @hide + */ + public boolean isAccessibilityServicePermittedByAdmin(@NonNull ComponentName admin, + @NonNull String packageName, int userHandle) { + if (mService != null) { + try { + return mService.isAccessibilityServicePermittedByAdmin(admin, packageName, + userHandle); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + return false; + } + + /** * Returns the list of accessibility services permitted by the device or profiles * owners of this user. * @@ -4146,6 +4211,28 @@ public class DevicePolicyManager { } /** + * Called by the system to check if a specific input method is disabled by admin. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param packageName Input method package name that needs to be checked. + * @param userHandle user id the admin is running as. + * @return true if the input method is permitted, otherwise false. + * + * @hide + */ + public boolean isInputMethodPermittedByAdmin(@NonNull ComponentName admin, + @NonNull String packageName, int userHandle) { + if (mService != null) { + try { + return mService.isInputMethodPermittedByAdmin(admin, packageName, userHandle); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + return false; + } + + /** * Returns the list of input methods permitted by the device or profiles * owners of the current user. (*Not* calling user, due to a limitation in InputMethodManager.) * diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index b57e1b7d8081..c6a53443b51c 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -174,10 +174,12 @@ interface IDevicePolicyManager { boolean setPermittedAccessibilityServices(in ComponentName admin,in List packageList); List getPermittedAccessibilityServices(in ComponentName admin); List getPermittedAccessibilityServicesForUser(int userId); + boolean isAccessibilityServicePermittedByAdmin(in ComponentName admin, String packageName, int userId); boolean setPermittedInputMethods(in ComponentName admin,in List packageList); List getPermittedInputMethods(in ComponentName admin); List getPermittedInputMethodsForCurrentUser(); + boolean isInputMethodPermittedByAdmin(in ComponentName admin, String packageName, int userId); boolean setApplicationHidden(in ComponentName admin, in String packageName, boolean hidden); boolean isApplicationHidden(in ComponentName admin, in String packageName); diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java index b2ca023a017f..5398e7f2dc95 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/core/java/android/app/job/JobInfo.java @@ -24,6 +24,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; import android.util.Log; +import static android.util.TimeUtils.formatForLogging; import java.util.ArrayList; @@ -640,12 +641,14 @@ public class JobInfo implements Parcelable { } JobInfo job = new JobInfo(this); if (job.intervalMillis != job.getIntervalMillis()) { - Log.w(TAG, "Specified interval is less than minimum interval. Clamped to " - + job.getIntervalMillis()); + Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is " + + formatForLogging(mIntervalMillis) + ". Clamped to " + + formatForLogging(job.getIntervalMillis())); } if (job.flexMillis != job.getFlexMillis()) { - Log.w(TAG, "Specified flex is less than minimum flex. Clamped to " - + job.getFlexMillis()); + Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is " + + formatForLogging(mFlexMillis) + ". Clamped to " + + formatForLogging(job.getFlexMillis())); } return job; } diff --git a/core/java/android/app/usage/DataUsagePolicy.java b/core/java/android/app/usage/DataUsagePolicy.java new file mode 100644 index 000000000000..5a5dcbc0ba2c --- /dev/null +++ b/core/java/android/app/usage/DataUsagePolicy.java @@ -0,0 +1,174 @@ +/** + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package android.app.usage; + +import android.net.ConnectivityManager; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.IntArray; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +/** + * Defines a policy for data usage callbacks, made through {@link DataUsagePolicy.Builder} and used + * to be notified on data usage via {@link NetworkStatsManager#registerDataUsageCallback}. + */ +public class DataUsagePolicy { + + /** + * Network type to be monitored, as defined in {@link ConnectivityManager}, e.g. + * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} etc. + */ + public final int networkType; + + /** + * Set of subscriber ids to be monitored for the given network type. May be empty if not + * applicable. + * <p>Should not be modified once created. + */ + public final String[] subscriberIds; + + /** + * Set of UIDs of which to monitor data usage. + * + * <p>If not {@code null}, the caller will be notified when any of the uids exceed + * the given threshold. If empty all uids for which the calling process has access + * to stats will be monitored. + * <p>Should not be modified once created. + */ + public final int[] uids; + + /** + * Threshold in bytes to be notified on. + */ + public final long thresholdInBytes; + + /** + * @hide + */ + DataUsagePolicy(int networkType, String[] subscriberIds, int[] uids, + long thresholdInBytes) { + this.networkType = networkType; + this.subscriberIds = subscriberIds; + this.uids = uids; + this.thresholdInBytes = thresholdInBytes; + } + + /** + * Builder used to create {@link DataUsagePolicy} objects. + */ + public static class Builder { + private static final int INVALID_NETWORK_TYPE = -1; + private int mNetworkType = INVALID_NETWORK_TYPE; + private List<String> mSubscriberList = new ArrayList<>(); + private IntArray mUids = new IntArray(); + private long mThresholdInBytes; + + /** + * Default constructor for Builder. + */ + public Builder() {} + + /** + * Build {@link DataUsagePolicy} given the current policies. + */ + public DataUsagePolicy build() { + if (mNetworkType == INVALID_NETWORK_TYPE) { + throw new IllegalArgumentException( + "DataUsagePolicy requires a valid network type to be set"); + } + return new DataUsagePolicy(mNetworkType, + mSubscriberList.toArray(new String[mSubscriberList.size()]), + mUids.toArray(), mThresholdInBytes); + } + + /** + * Specifies that the given {@code subscriberId} should be monitored. + * + * @param subscriberId the subscriber id of the network interface. + */ + public Builder addSubscriberId(String subscriberId) { + mSubscriberList.add(subscriberId); + return this; + } + + /** + * Specifies that the given {@code uid} should be monitored. + */ + public Builder addUid(int uid) { + mUids.add(uid); + return this; + } + + /** + * Specifies that the callback should monitor the given network. It is mandatory + * to set one. + * + * @param networkType As defined in {@link ConnectivityManager}, e.g. + * {@link ConnectivityManager#TYPE_MOBILE}, + * {@link ConnectivityManager#TYPE_WIFI}, etc. + */ + public Builder setNetworkType(int networkType) { + mNetworkType = networkType; + return this; + } + + /** + * Sets the threshold in bytes on which the listener should be called. The framework may + * impose a minimum threshold to avoid too many notifications to be triggered. + */ + public Builder setThreshold(long thresholdInBytes) { + mThresholdInBytes = thresholdInBytes; + return this; + } + } + + @Override + public String toString() { + return "DataUsagePolicy [ networkType=" + networkType + + ", subscriberIds=" + Arrays.toString(subscriberIds) + + ", uids=" + Arrays.toString(uids) + + ", thresholdInBytes=" + thresholdInBytes + " ]"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DataUsagePolicy == false) return false; + DataUsagePolicy that = (DataUsagePolicy) obj; + return that.networkType == this.networkType + && Arrays.deepEquals(that.subscriberIds, this.subscriberIds) + && Arrays.equals(that.uids, this.uids) + && that.thresholdInBytes == this.thresholdInBytes; + } + + @Override + public int hashCode() { + // Start with a non-zero constant. + int result = 17; + + // Include a hash for each field. + result = 31 * result + networkType; + result = 31 * result + Arrays.deepHashCode(subscriberIds); + result = 31 * result + Arrays.hashCode(uids); + result = 31 * result + (int) (thresholdInBytes ^ (thresholdInBytes >>> 32)); + + return result; + } +} diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 4dc636b078b7..13aeef0058bb 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,12 +16,17 @@ package android.app.usage; +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.Nullable; import android.app.usage.NetworkStats.Bucket; import android.content.Context; import android.net.ConnectivityManager; +import android.net.DataUsageRequest; import android.net.NetworkIdentity; import android.net.NetworkTemplate; import android.os.Build; +import android.os.Handler; import android.os.RemoteException; import android.util.Log; @@ -288,6 +293,62 @@ public class NetworkStatsManager { return result; } + /** + * Registers to receive notifications about data usage on specified networks and uids. + * The callbacks will continue to be called as long as the process is live or + * {@link #unregisterDataUsageCallback} is called. + * + * @param policy {@link DataUsagePolicy} describing this request. + * @param callback The {@link DataUsageCallback} that the system will call when data usage + * has exceeded the specified threshold. + */ + public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback) { + registerDataUsageCallback(policy, callback, null /* handler */); + } + + /** + * Registers to receive notifications about data usage on specified networks and uids. + * The callbacks will continue to be called as long as the process is live or + * {@link #unregisterDataUsageCallback} is called. + * + * @param policy {@link DataUsagePolicy} describing this request. + * @param callback The {@link DataUsageCallback} that the system will call when data usage + * has exceeded the specified threshold. + * @param handler to dispatch callback events through, otherwise if {@code null} it uses + * the calling thread. + */ + public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback, + @Nullable Handler handler) { + checkNotNull(policy, "DataUsagePolicy cannot be null"); + checkNotNull(callback, "DataUsageCallback cannot be null"); + + // TODO: Implement stub. + } + + /** + * Unregisters callbacks on data usage. + * + * @param callback The {@link DataUsageCallback} used when registering. + */ + public void unregisterDataUsageCallback(DataUsageCallback callback) { + checkNotNull(callback, "DataUsageCallback cannot be null"); + + // TODO: Implement stub. + } + + /** + * Base class for data usage callbacks. Should be extended by applications wanting + * notifications. + */ + public static class DataUsageCallback { + /** + * Called when data usage has reached the given policy threshold. + */ + public void onLimitReached() {} + + private DataUsageRequest request; + } + private static NetworkTemplate createTemplate(int networkType, String subscriberId) { NetworkTemplate template = null; switch (networkType) { diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 55b8f0367885..bed91ecafb96 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -29,6 +29,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -49,6 +50,8 @@ import android.widget.RemoteViews.OnClickHandler; import android.widget.RemoteViewsAdapter.RemoteAdapterConnectionCallback; import android.widget.TextView; +import java.util.concurrent.Executor; + /** * Provides the glue to show AppWidget views. This class offers automatic animation * between updates, and will try recycling old views for each incoming @@ -87,6 +90,9 @@ public class AppWidgetHostView extends FrameLayout { Paint mOldPaint = new Paint(); private OnClickHandler mOnClickHandler; + private Executor mAsyncExecutor; + private CancellationSignal mLastExecutionSignal; + /** * Create a host view. Uses default fade animations. */ @@ -340,6 +346,22 @@ public class AppWidgetHostView extends FrameLayout { } /** + * Sets an executor which can be used for asynchronously inflating and applying the remoteviews. + * @see {@link RemoteViews#applyAsync(Context, ViewGroup, RemoteViews.OnViewAppliedListener, Executor)} + * + * @param executor the executor to use or null. + * @hide + */ + public void setAsyncExecutor(Executor executor) { + if (mLastExecutionSignal != null) { + mLastExecutionSignal.cancel(); + mLastExecutionSignal = null; + } + + mAsyncExecutor = executor; + } + + /** * Update the AppWidgetProviderInfo for this view, and reset it to the * initial layout. */ @@ -380,6 +402,11 @@ public class AppWidgetHostView extends FrameLayout { } } + if (mLastExecutionSignal != null) { + mLastExecutionSignal.cancel(); + mLastExecutionSignal = null; + } + if (remoteViews == null) { if (mViewMode == VIEW_MODE_DEFAULT) { // We've already done this -- nothing to do. @@ -389,6 +416,10 @@ public class AppWidgetHostView extends FrameLayout { mLayoutId = -1; mViewMode = VIEW_MODE_DEFAULT; } else { + if (mAsyncExecutor != null) { + inflateAsync(remoteViews); + return; + } // Prepare a local reference to the remote Context so we're ready to // inflate any requested LayoutParams. mRemoteContext = getRemoteContext(); @@ -421,6 +452,10 @@ public class AppWidgetHostView extends FrameLayout { mViewMode = VIEW_MODE_CONTENT; } + applyContent(content, recycled, exception); + } + + private void applyContent(View content, boolean recycled, Exception exception) { if (content == null) { if (mViewMode == VIEW_MODE_ERROR) { // We've already done this -- nothing to do. @@ -452,6 +487,68 @@ public class AppWidgetHostView extends FrameLayout { } } + private void inflateAsync(RemoteViews remoteViews) { + // Prepare a local reference to the remote Context so we're ready to + // inflate any requested LayoutParams. + mRemoteContext = getRemoteContext(); + int layoutId = remoteViews.getLayoutId(); + + // If our stale view has been prepared to match active, and the new + // layout matches, try recycling it + if (layoutId == mLayoutId && mView != null) { + try { + mLastExecutionSignal = remoteViews.reapplyAsync(mContext, + mView, + mAsyncExecutor, + new ViewApplyListener(remoteViews, layoutId, true), + mOnClickHandler); + } catch (Exception e) { + // Reapply failed. Try apply + } + } + if (mLastExecutionSignal == null) { + mLastExecutionSignal = remoteViews.applyAsync(mContext, + this, + mAsyncExecutor, + new ViewApplyListener(remoteViews, layoutId, false), + mOnClickHandler); + } + } + + private class ViewApplyListener implements RemoteViews.OnViewAppliedListener { + private final RemoteViews mViews; + private final boolean mIsReapply; + private final int mLayoutId; + + public ViewApplyListener(RemoteViews views, int layoutId, boolean isReapply) { + mViews = views; + mLayoutId = layoutId; + mIsReapply = isReapply; + } + + @Override + public void onViewApplied(View v) { + AppWidgetHostView.this.mLayoutId = mLayoutId; + mViewMode = VIEW_MODE_CONTENT; + + applyContent(v, mIsReapply, null); + } + + @Override + public void onError(Exception e) { + if (mIsReapply) { + // Try a fresh replay + mLastExecutionSignal = mViews.applyAsync(mContext, + AppWidgetHostView.this, + mAsyncExecutor, + new ViewApplyListener(mViews, mLayoutId, false), + mOnClickHandler); + } else { + applyContent(null, false, e); + } + } + } + /** * Process data-changed notifications for the specified view in the specified * set of {@link RemoteViews} views. diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 622aad9c98bf..4918914ec9d5 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -342,9 +342,7 @@ public abstract class Context { * {@link android.R.attr#isolatedProcess isolated}, * {@link android.R.attr#externalService external} service. This binds the service into the * calling application's package, rather than the package in which the service is declared. - * @hide */ - @SystemApi public static final int BIND_EXTERNAL_SERVICE = 0x80000000; /** diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index eecf0de5afa8..6bd285a6c394 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -52,7 +52,6 @@ public class ServiceInfo extends ComponentInfo * Bit in {@link #flags}: If set, the service can be bound and run in the * calling application's package, rather than the package in which it is * declared. Set from {@link android.R.attr#externalService} attribute. - * @hide */ public static final int FLAG_EXTERNAL_SERVICE = 0x0004; diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 7db5a0889a35..be4f89567f51 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -715,7 +715,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * about setLocales() has changed locale directly. */ private void fixUpLocaleList() { if ((locale == null && !mLocaleList.isEmpty()) || - (locale != null && !locale.equals(mLocaleList.getPrimary()))) { + (locale != null && !locale.equals(mLocaleList.get(0)))) { mLocaleList = new LocaleList(locale); } } @@ -1269,7 +1269,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration localeArray[i] = Locale.forLanguageTag(source.readString()); } mLocaleList = new LocaleList(localeArray); - locale = mLocaleList.getPrimary(); + locale = mLocaleList.get(0); userSetLocale = (source.readInt()==1); touchscreen = source.readInt(); @@ -1435,7 +1435,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration */ public void setLocales(@Nullable LocaleList locales) { mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales; - locale = mLocaleList.getPrimary(); + locale = mLocaleList.get(0); setLayoutDirection(locale); } @@ -1900,7 +1900,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES); configOut.mLocaleList = LocaleList.forLanguageTags(localesStr); - configOut.locale = configOut.mLocaleList.getPrimary(); + configOut.locale = configOut.mLocaleList.get(0); configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN, TOUCHSCREEN_UNDEFINED); diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 4967d05e2727..915fae0ff6b5 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -381,7 +381,7 @@ public class Resources { private PluralRules getPluralRule() { synchronized (sSync) { if (mPluralRule == null) { - mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary()); + mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); } return mPluralRule; } @@ -444,7 +444,7 @@ public class Resources { @NonNull public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException { final String raw = getString(id); - return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs); + return String.format(mConfiguration.getLocales().get(0), raw, formatArgs); } /** @@ -475,7 +475,7 @@ public class Resources { public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs) throws NotFoundException { String raw = getQuantityText(id, quantity).toString(); - return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs); + return String.format(mConfiguration.getLocales().get(0), raw, formatArgs); } /** @@ -1971,7 +1971,7 @@ public class Resources { } mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc, - adjustLanguageTag(locales.getPrimary().toLanguageTag()), + adjustLanguageTag(locales.get(0).toLanguageTag()), mConfiguration.orientation, mConfiguration.touchscreen, mConfiguration.densityDpi, mConfiguration.keyboard, @@ -1996,7 +1996,7 @@ public class Resources { } synchronized (sSync) { if (mPluralRule != null) { - mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary()); + mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); } } } diff --git a/core/java/android/net/DataUsageRequest.aidl b/core/java/android/net/DataUsageRequest.aidl new file mode 100644 index 000000000000..d1937c7b8c62 --- /dev/null +++ b/core/java/android/net/DataUsageRequest.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2016, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable DataUsageRequest; diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java new file mode 100644 index 000000000000..0e46f4c0cbdf --- /dev/null +++ b/core/java/android/net/DataUsageRequest.java @@ -0,0 +1,143 @@ +/** + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package android.net; + +import android.net.NetworkTemplate; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Defines a request to register a callbacks. Used to be notified on data usage via + * {@link android.app.usage.NetworkStatsManager#registerDataUsageCallback}. + * If no {@code uid}s are set, callbacks are restricted to device-owners, + * carrier-privileged apps, or system apps. + */ +public class DataUsageRequest implements Parcelable { + + /** + * @hide + */ + public static final int REQUEST_ID_UNSET = 0; + + /** + * Identifies the request. {@link DataUsageRequest}s should only be constructed by + * the Framework and it is used internally to identify the request. + * @hide + */ + public final int requestId; + + /** + * Set of {@link NetworkTemplate}s describing the networks to monitor. + * @hide + */ + public final NetworkTemplate[] templates; + + /** + * Set of UIDs of which to monitor data usage. + * + * <p>If not {@code null}, the caller will be notified when any of the uids exceed + * the given threshold. If {@code null} all uids for which the calling process has access + * to stats will be monitored. + * @hide + */ + public final int[] uids; + + /** + * Threshold in bytes to be notified on. + * @hide + */ + public final long thresholdInBytes; + + /** + * @hide + */ + public DataUsageRequest(int requestId, NetworkTemplate[] templates, int[] uids, + long thresholdInBytes) { + this.requestId = requestId; + this.templates = templates; + this.uids = uids; + this.thresholdInBytes = thresholdInBytes; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(requestId); + dest.writeTypedArray(templates, flags); + dest.writeIntArray(uids); + dest.writeLong(thresholdInBytes); + } + + public static final Creator<DataUsageRequest> CREATOR = + new Creator<DataUsageRequest>() { + @Override + public DataUsageRequest createFromParcel(Parcel in) { + int requestId = in.readInt(); + NetworkTemplate[] templates = in.createTypedArray(NetworkTemplate.CREATOR); + int[] uids = in.createIntArray(); + long thresholdInBytes = in.readLong(); + DataUsageRequest result = new DataUsageRequest(requestId, + templates, uids, thresholdInBytes); + return result; + } + + @Override + public DataUsageRequest[] newArray(int size) { + return new DataUsageRequest[size]; + } + }; + + @Override + public String toString() { + return "DataUsageRequest [ requestId=" + requestId + + ", networkTemplates=" + Arrays.toString(templates) + + ", uids=" + Arrays.toString(uids) + + ", thresholdInBytes=" + thresholdInBytes + " ]"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DataUsageRequest == false) return false; + DataUsageRequest that = (DataUsageRequest) obj; + return that.requestId == this.requestId + && Arrays.deepEquals(that.templates, this.templates) + && Arrays.equals(that.uids, this.uids) + && that.thresholdInBytes == this.thresholdInBytes; + } + + @Override + public int hashCode() { + // Start with a non-zero constant. + int result = 17; + + // Include a hash for each field. + result = 31 * result + requestId; + result = 31 * result + Arrays.deepHashCode(templates); + result = 31 * result + Arrays.hashCode(uids); + result = 31 * result + (int) (thresholdInBytes ^ (thresholdInBytes >>> 32)); + + return result; + } + +} diff --git a/core/java/android/nfc/tech/NfcF.java b/core/java/android/nfc/tech/NfcF.java index b3e3ab6251c8..44871212daef 100644 --- a/core/java/android/nfc/tech/NfcF.java +++ b/core/java/android/nfc/tech/NfcF.java @@ -98,8 +98,13 @@ public final class NfcF extends BasicTagTechnology { /** * Send raw NFC-F commands to the tag and receive the response. * - * <p>Applications must not append the SoD (length) or EoD (CRC) to the payload, - * it will be automatically calculated. + * <p>Applications must not prefix the SoD (preamble and sync code) + * and/or append the EoD (CRC) to the payload, it will be automatically calculated. + * + * <p>A typical NFC-F frame for this method looks like: + * <pre> + * LENGTH (1 byte) --- CMD (1 byte) -- IDm (8 bytes) -- PARAMS (LENGTH - 10 bytes) + * </pre> * * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum amount of bytes * that can be sent with {@link #transceive}. diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java index 54d1090d1327..fc804e592148 100644 --- a/core/java/android/os/ShellCommand.java +++ b/core/java/android/os/ShellCommand.java @@ -234,6 +234,16 @@ public abstract class ShellCommand { } } + public String peekNextArg() { + if (mCurArgData != null) { + return mCurArgData; + } else if (mArgPos < mArgs.length) { + return mArgs[mArgPos]; + } else { + return null; + } + } + /** * Return the next argument on the command line, whatever it is; if there are * no arguments left, throws an IllegalArgumentException to report this to the user. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5535eaa0726d..7830142d4e4b 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -670,14 +670,14 @@ public final class Settings { "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"; /** - * Activity Action: Ask the user to allow an to ignore battery optimizations (that is, + * Activity Action: Ask the user to allow an app to ignore battery optimizations (that is, * put them on the whitelist of apps shown by * {@link #ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS}). For an app to use this, it also * must hold the {@link android.Manifest.permission#REQUEST_IGNORE_BATTERY_OPTIMIZATIONS} * permission. * <p><b>Note:</b> most applications should <em>not</em> use this; there are many facilities * provided by the platform for applications to operate correctly in the various power - * saving mode. This is only for unusual applications that need to deeply control their own + * saving modes. This is only for unusual applications that need to deeply control their own * execution, at the potential expense of the user's battery life. Note that these applications * greatly run the risk of showing to the user as high power consumers on their device.</p> * <p> @@ -695,6 +695,24 @@ public final class Settings { "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; /** + * Activity Action: Show screen for controlling which apps can ignore background data + * restrictions. + * <p> + * Input: if the Intent's data URI is set with an application name (using the "package" schema, + * like "package:com.my.app"), then when the screen is displayed it will focus on such app. If + * the data is not set, it will just open the screen. + * <p> + * Output: Nothing. + * <p> + * Applications can also use {@link android.net.ConnectivityManager#getRestrictBackgroundStatus + * ConnectivityManager#getRestrictBackgroundStatus()} to determine the status of the background + * data restrictions for them. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = + "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS"; + + /** * @hide * Activity Action: Show the "app ops" settings screen. * <p> @@ -3851,7 +3869,6 @@ public final class Settings { MOVED_TO_GLOBAL.add(Settings.Global.DATA_ROAMING); MOVED_TO_GLOBAL.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED); MOVED_TO_GLOBAL.add(Settings.Global.DEVICE_PROVISIONED); - MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_DENSITY_FORCED); MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_SIZE_FORCED); MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE); MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE); @@ -5086,6 +5103,15 @@ public final class Settings { "disabled_print_services"; /** + * The saved value for WindowManagerService.setForcedDisplayDensity() + * formatted as a single integer representing DPI. If unset, then use + * the real display density. + * + * @hide + */ + public static final String DISPLAY_DENSITY_FORCED = "display_density_forced"; + + /** * Setting to always use the default text-to-speech settings regardless * of the application settings. * 1 = override application settings, @@ -6517,13 +6543,6 @@ public final class Settings { public static final String DEVICE_PROVISIONED = "device_provisioned"; /** - * The saved value for WindowManagerService.setForcedDisplayDensity(). - * One integer in dpi. If unset, then use the real display density. - * @hide - */ - public static final String DISPLAY_DENSITY_FORCED = "display_density_forced"; - - /** * The saved value for WindowManagerService.setForcedDisplaySize(). * Two integers separated by a comma. If unset, then use the real display size. * @hide diff --git a/core/java/android/text/BidiFormatter.java b/core/java/android/text/BidiFormatter.java index a535480e3ac0..675803c7b7bd 100644 --- a/core/java/android/text/BidiFormatter.java +++ b/core/java/android/text/BidiFormatter.java @@ -293,7 +293,7 @@ public final class BidiFormatter { * directionality is determined by scanning the end of the string, the overall directionality is * given explicitly by a heuristic to estimate the {@code str}'s directionality. * - * @param str String after which the mark may need to appear. + * @param str CharSequence after which the mark may need to appear. * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s * directionality. * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context; @@ -301,7 +301,7 @@ public final class BidiFormatter { * * @hide */ - public String markAfter(String str, TextDirectionHeuristic heuristic) { + public String markAfter(CharSequence str, TextDirectionHeuristic heuristic) { final boolean isRtl = heuristic.isRtl(str, 0, str.length()); // getExitDir() is called only if needed (short-circuit). if (!mIsRtlContext && (isRtl || getExitDir(str) == DIR_RTL)) { @@ -322,7 +322,7 @@ public final class BidiFormatter { * entry directionality is determined by scanning the beginning of the string, the overall * directionality is given explicitly by a heuristic to estimate the {@code str}'s directionality. * - * @param str String before which the mark may need to appear. + * @param str CharSequence before which the mark may need to appear. * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s * directionality. * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context; @@ -330,7 +330,7 @@ public final class BidiFormatter { * * @hide */ - public String markBefore(String str, TextDirectionHeuristic heuristic) { + public String markBefore(CharSequence str, TextDirectionHeuristic heuristic) { final boolean isRtl = heuristic.isRtl(str, 0, str.length()); // getEntryDir() is called only if needed (short-circuit). if (!mIsRtlContext && (isRtl || getEntryDir(str) == DIR_RTL)) { @@ -350,6 +350,13 @@ public final class BidiFormatter { * false. */ public boolean isRtl(String str) { + return isRtl((CharSequence) str); + } + + /** + * @hide + */ + public boolean isRtl(CharSequence str) { return mDefaultTextDirectionHeuristic.isRtl(str, 0, str.length()); } @@ -384,9 +391,16 @@ public final class BidiFormatter { * {@code null}. */ public String unicodeWrap(String str, TextDirectionHeuristic heuristic, boolean isolate) { + return unicodeWrap((CharSequence) str, heuristic, isolate).toString(); + } + + /** + * @hide + */ + public CharSequence unicodeWrap(CharSequence str, TextDirectionHeuristic heuristic, boolean isolate) { if (str == null) return null; final boolean isRtl = heuristic.isRtl(str, 0, str.length()); - StringBuilder result = new StringBuilder(); + SpannableStringBuilder result = new SpannableStringBuilder(); if (getStereoReset() && isolate) { result.append(markBefore(str, isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR)); @@ -402,7 +416,7 @@ public final class BidiFormatter { result.append(markAfter(str, isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR)); } - return result.toString(); + return result; } /** @@ -419,6 +433,14 @@ public final class BidiFormatter { } /** + * @hide + */ + public CharSequence unicodeWrap(CharSequence str, TextDirectionHeuristic heuristic) { + return unicodeWrap(str, heuristic, true /* isolate */); + } + + + /** * Operates like {@link #unicodeWrap(String, TextDirectionHeuristic, boolean)}, but uses the * formatter's default direction estimation algorithm. * @@ -432,6 +454,13 @@ public final class BidiFormatter { } /** + * @hide + */ + public CharSequence unicodeWrap(CharSequence str, boolean isolate) { + return unicodeWrap(str, mDefaultTextDirectionHeuristic, isolate); + } + + /** * Operates like {@link #unicodeWrap(String, TextDirectionHeuristic, boolean)}, but uses the * formatter's default direction estimation algorithm and assumes {@code isolate} is true. * @@ -442,6 +471,13 @@ public final class BidiFormatter { return unicodeWrap(str, mDefaultTextDirectionHeuristic, true /* isolate */); } + /** + * @hide + */ + public CharSequence unicodeWrap(CharSequence str) { + return unicodeWrap(str, mDefaultTextDirectionHeuristic, true /* isolate */); + } + private static BidiFormatter getDefaultInstanceFromContext(boolean isRtlContext) { return isRtlContext ? DEFAULT_RTL_INSTANCE : DEFAULT_LTR_INSTANCE; } @@ -477,7 +513,7 @@ public final class BidiFormatter { * * @param str the string to check. */ - private static int getExitDir(String str) { + private static int getExitDir(CharSequence str) { return new DirectionalityEstimator(str, false /* isHtml */).getExitDir(); } @@ -494,7 +530,7 @@ public final class BidiFormatter { * * @param str the string to check. */ - private static int getEntryDir(String str) { + private static int getEntryDir(CharSequence str) { return new DirectionalityEstimator(str, false /* isHtml */).getEntryDir(); } @@ -532,7 +568,7 @@ public final class BidiFormatter { /** * The text to be scanned. */ - private final String text; + private final CharSequence text; /** * Whether the text to be scanned is to be treated as HTML, i.e. skipping over tags and @@ -565,7 +601,7 @@ public final class BidiFormatter { * @param isHtml Whether the text to be scanned is to be treated as HTML, i.e. skipping over * tags and entities. */ - DirectionalityEstimator(String text, boolean isHtml) { + DirectionalityEstimator(CharSequence text, boolean isHtml) { this.text = text; this.isHtml = isHtml; length = text.length(); @@ -896,4 +932,4 @@ public final class BidiFormatter { return Character.DIRECTIONALITY_OTHER_NEUTRALS; } } -}
\ No newline at end of file +} diff --git a/core/java/android/text/style/LocaleSpan.java b/core/java/android/text/style/LocaleSpan.java index 117de77442fb..4f687c857362 100644 --- a/core/java/android/text/style/LocaleSpan.java +++ b/core/java/android/text/style/LocaleSpan.java @@ -97,12 +97,12 @@ public class LocaleSpan extends MetricAffectingSpan implements ParcelableSpan { * @return The {@link Locale} for this span. If multiple locales are associated with this * span, only the first locale is returned. {@code null} if no {@link Locale} is specified. * - * @see LocaleList#getPrimary() + * @see LocaleList#get() * @see #getLocales() */ @Nullable public Locale getLocale() { - return mLocales.getPrimary(); + return mLocales.get(0); } /** diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java index 90a20bc2ab24..fc39004cf2cb 100644 --- a/core/java/android/util/LocaleList.java +++ b/core/java/android/util/LocaleList.java @@ -47,12 +47,7 @@ public final class LocaleList implements Parcelable { private static final LocaleList sEmptyLocaleList = new LocaleList(); public Locale get(int location) { - return location < mList.length ? mList[location] : null; - } - - @Nullable - public Locale getPrimary() { - return mList.length == 0 ? null : get(0); + return (0 <= location && location < mList.length) ? mList[location] : null; } public boolean isEmpty() { @@ -464,7 +459,7 @@ public final class LocaleList implements Parcelable { // someone has called Locale.setDefault() since we last set or adjusted the default // locale list. So let's recalculate the locale list. if (sDefaultLocaleList != null - && defaultLocale.equals(sDefaultLocaleList.getPrimary())) { + && defaultLocale.equals(sDefaultLocaleList.get(0))) { // 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; diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java index 29a72fdf2288..78d5bcd90624 100644 --- a/core/java/android/util/PathParser.java +++ b/core/java/android/util/PathParser.java @@ -104,7 +104,6 @@ public class PathParser { } super.finalize(); } - } /** diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java index 501c6e9e25e5..b9a7421fe14c 100644 --- a/core/java/android/view/NotificationHeaderView.java +++ b/core/java/android/view/NotificationHeaderView.java @@ -21,7 +21,6 @@ import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.RemoteViews; import android.widget.TextView; @@ -35,7 +34,7 @@ import java.util.ArrayList; @RemoteViews.RemoteView public class NotificationHeaderView extends ViewGroup { public static final int NO_COLOR = -1; - private final int mHeaderMinWidth; + private final int mChildMinWidth; private final int mExpandTopPadding; private final int mContentEndMargin; private View mAppName; @@ -46,6 +45,7 @@ public class NotificationHeaderView extends ViewGroup { private View mIcon; private TextView mChildCount; private View mProfileBadge; + private View mInfo; private int mIconColor; private int mOriginalNotificationColor; private boolean mGroupHeader; @@ -66,7 +66,7 @@ public class NotificationHeaderView extends ViewGroup { public NotificationHeaderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mHeaderMinWidth = getResources().getDimensionPixelSize( + mChildMinWidth = getResources().getDimensionPixelSize( com.android.internal.R.dimen.notification_header_shrink_min_width); mContentEndMargin = getResources().getDimensionPixelSize( com.android.internal.R.dimen.notification_content_margin_end); @@ -82,6 +82,7 @@ public class NotificationHeaderView extends ViewGroup { mIcon = findViewById(com.android.internal.R.id.icon); mChildCount = (TextView) findViewById(com.android.internal.R.id.number_of_children); mProfileBadge = findViewById(com.android.internal.R.id.profile_badge); + mInfo = findViewById(com.android.internal.R.id.header_content_info); } @Override @@ -109,14 +110,23 @@ public class NotificationHeaderView extends ViewGroup { } if (totalWidth > givenWidth) { int overFlow = totalWidth - givenWidth; - // We are overflowing, lets shrink + // We are overflowing, lets shrink the info first + final int infoWidth = mInfo.getMeasuredWidth(); + if (mInfo.getVisibility() != GONE && infoWidth > mChildMinWidth) { + int newSize = infoWidth - Math.min(infoWidth - mChildMinWidth, overFlow); + int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST); + mInfo.measure(childWidthSpec, wrapContentHeightSpec); + overFlow -= infoWidth - newSize; + } + // still overflowing, lets shrink the app name now final int appWidth = mAppName.getMeasuredWidth(); - if (mAppName.getVisibility() != GONE && appWidth > mHeaderMinWidth) { - int newSize = appWidth - Math.min(appWidth - mHeaderMinWidth, overFlow); + if (overFlow > 0 && mAppName.getVisibility() != GONE && appWidth > mChildMinWidth) { + int newSize = appWidth - Math.min(appWidth - mChildMinWidth, overFlow); int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST); mAppName.measure(childWidthSpec, wrapContentHeightSpec); overFlow -= appWidth - newSize; } + // still overflowing, finaly we shrink the subtext if (overFlow > 0 && mSubTextView.getVisibility() != GONE) { // we're still too big final int subTextWidth = mSubTextView.getMeasuredWidth(); @@ -124,12 +134,8 @@ public class NotificationHeaderView extends ViewGroup { int childWidthSpec = MeasureSpec.makeMeasureSpec(newSize, MeasureSpec.AT_MOST); mSubTextView.measure(childWidthSpec, wrapContentHeightSpec); } - totalWidth = givenWidth; } - if (mProfileBadge.getVisibility() != View.GONE) { - totalWidth = givenWidth; - } - setMeasuredDimension(totalWidth, givenHeight); + setMeasuredDimension(givenWidth, givenHeight); } @Override @@ -275,18 +281,16 @@ public class NotificationHeaderView extends ViewGroup { mTouchRects.clear(); addRectAroundViewView(mIcon); addRectAroundViewView(mExpandButton); - addInBetweenRect(); + addWidthRect(); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } - private void addInBetweenRect() { - final Rect r = new Rect(); + private void addWidthRect() { + Rect r = new Rect(); r.top = 0; r.bottom = (int) (32 * getResources().getDisplayMetrics().density); - Rect leftRect = mTouchRects.get(0); - r.left = leftRect.right; - Rect rightRect = mTouchRects.get(1); - r.right = rightRect.left; + r.left = 0; + r.right = getWidth(); mTouchRects.add(r); } diff --git a/core/java/android/view/RemotableViewMethod.java b/core/java/android/view/RemotableViewMethod.java index 4318290affc4..e5cae84942f9 100644 --- a/core/java/android/view/RemotableViewMethod.java +++ b/core/java/android/view/RemotableViewMethod.java @@ -29,6 +29,12 @@ import java.lang.annotation.Target; @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface RemotableViewMethod { + /** + * @return Method name which can be called on a background thread. It should have the + * same arguments as the original method and should return a {@link Runnable} (or null) + * which will be called on the UI thread. + */ + String asyncImpl() default ""; } diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index 2aace0f30139..3122c0be30fe 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -22,7 +22,6 @@ import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Rect; -import android.graphics.drawable.AnimatedVectorDrawable; /** * <p>A display list records a series of graphics related operations and can replay @@ -136,6 +135,9 @@ public class RenderNode { private RenderNode(String name, View owningView) { mNativeRenderNode = nCreate(name); mOwningView = owningView; + if (mOwningView instanceof SurfaceView) { + nRequestPositionUpdates(mNativeRenderNode, (SurfaceView) mOwningView); + } } /** @@ -772,14 +774,6 @@ public class RenderNode { mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this); } - public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimator animatorSet) { - if (mOwningView == null || mOwningView.mAttachInfo == null) { - throw new IllegalStateException("Cannot start this animator on a detached view!"); - } - nAddAnimator(mNativeRenderNode, animatorSet.getAnimatorNativePtr()); - mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this); - } - public void endAllAnimators() { nEndAllAnimators(mNativeRenderNode); } @@ -863,6 +857,8 @@ public class RenderNode { private static native void nOutput(long renderNode); private static native int nGetDebugSize(long renderNode); + private static native void nRequestPositionUpdates(long renderNode, SurfaceView callback); + /////////////////////////////////////////////////////////////////////////// // Animations /////////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/view/RenderNodeAnimatorSetHelper.java b/core/java/android/view/RenderNodeAnimatorSetHelper.java deleted file mode 100644 index ba592d29fa3d..000000000000 --- a/core/java/android/view/RenderNodeAnimatorSetHelper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.view; - -import android.animation.TimeInterpolator; -import com.android.internal.view.animation.FallbackLUTInterpolator; -import com.android.internal.view.animation.NativeInterpolatorFactory; -import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; - -/** - * This is a helper class to get access to methods and fields needed for RenderNodeAnimatorSet - * that are internal or package private to android.view package. - * - * @hide - */ -public class RenderNodeAnimatorSetHelper { - - public static RenderNode getTarget(DisplayListCanvas recordingCanvas) { - return recordingCanvas.mNode; - } - - public static long createNativeInterpolator(TimeInterpolator interpolator, long - duration) { - if (interpolator == null) { - // create LinearInterpolator - return NativeInterpolatorFactoryHelper.createLinearInterpolator(); - } else if (RenderNodeAnimator.isNativeInterpolator(interpolator)) { - return ((NativeInterpolatorFactory)interpolator).createNativeInterpolator(); - } else { - return FallbackLUTInterpolator.createNativeInterpolator(interpolator, duration); - } - } - -} diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 5b48e2893fc7..a2960515da08 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -135,7 +135,7 @@ public class SurfaceView extends View { } }; - final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener + private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener = new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { @@ -143,6 +143,17 @@ public class SurfaceView extends View { } }; + private final ViewTreeObserver.OnPreDrawListener mDrawListener = + new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + // reposition ourselves where the surface is + mHaveFrame = getWidth() > 0 && getHeight() > 0; + updateWindow(false, false); + return true; + } + }; + boolean mRequestedVisible = false; boolean mWindowVisibility = false; boolean mViewVisibility = false; @@ -168,17 +179,9 @@ public class SurfaceView extends View { boolean mUpdateWindowNeeded; boolean mReportDrawNeeded; private Translator mTranslator; + private int mWindowInsetLeft; + private int mWindowInsetTop; - private final ViewTreeObserver.OnPreDrawListener mDrawListener = - new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - // reposition ourselves where the surface is - mHaveFrame = getWidth() > 0 && getHeight() > 0; - updateWindow(false, false); - return true; - } - }; private boolean mGlobalListenersAdded; public SurfaceView(Context context) { @@ -443,17 +446,17 @@ public class SurfaceView extends View { int myHeight = mRequestedHeight; if (myHeight <= 0) myHeight = getHeight(); - getLocationInWindow(mLocation); final boolean creating = mWindow == null; final boolean formatChanged = mFormat != mRequestedFormat; final boolean sizeChanged = mWindowSpaceWidth != myWidth || mWindowSpaceHeight != myHeight; final boolean visibleChanged = mVisible != mRequestedVisible; final boolean layoutSizeChanged = getWidth() != mLayout.width || getHeight() != mLayout.height; - final boolean positionChanged = mWindowSpaceLeft != mLocation[0] || mWindowSpaceTop != mLocation[1]; if (force || creating || formatChanged || sizeChanged || visibleChanged || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) { + getLocationInWindow(mLocation); + if (DEBUG) Log.i(TAG, "Changes: creating=" + creating + " format=" + formatChanged + " size=" + sizeChanged + " visible=" + visibleChanged @@ -643,24 +646,66 @@ public class SurfaceView extends View { TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y + " w=" + mLayout.width + " h=" + mLayout.height + ", frame=" + mSurfaceFrame); - } else if (positionChanged || layoutSizeChanged) { // Only the position has changed - mWindowSpaceLeft = mLocation[0]; - mWindowSpaceTop = mLocation[1]; - // For our size changed check, we keep mLayout.width and mLayout.height - // in view local space. - mLocation[0] = mLayout.width = getWidth(); - mLocation[1] = mLayout.height = getHeight(); + } else if (!isHardwareAccelerated()) { + getLocationInWindow(mLocation); + final boolean positionChanged = mWindowSpaceLeft != mLocation[0] + || mWindowSpaceTop != mLocation[1]; + if (positionChanged || layoutSizeChanged) { // Only the position has changed + mWindowSpaceLeft = mLocation[0]; + mWindowSpaceTop = mLocation[1]; + // For our size changed check, we keep mLayout.width and mLayout.height + // in view local space. + mLocation[0] = mLayout.width = getWidth(); + mLocation[1] = mLayout.height = getHeight(); - transformFromViewToWindowSpace(mLocation); + transformFromViewToWindowSpace(mLocation); - try { - mSession.repositionChild(mWindow, mWindowSpaceLeft, mWindowSpaceTop, - mLocation[0], mLocation[1], - viewRoot != null ? viewRoot.getNextFrameNumber() : -1, - mWinFrame); - } catch (RemoteException ex) { - Log.e(TAG, "Exception from relayout", ex); + try { + Log.d(TAG, String.format("updateWindowPosition UI, " + + "postion = [%d, %d, %d, %d]", mWindowSpaceLeft, mWindowSpaceTop, + mLocation[0], mLocation[1])); + mSession.repositionChild(mWindow, mWindowSpaceLeft, mWindowSpaceTop, + mLocation[0], mLocation[1], -1, mWinFrame); + } catch (RemoteException ex) { + Log.e(TAG, "Exception from relayout", ex); + } + } + } + } + + private Rect mRTLastReportedPosition = new Rect(); + + /** + * Called by native on RenderThread to update the window position + * @hide + */ + public final void updateWindowPositionRT(long frameNumber, + int left, int top, int right, int bottom) { + IWindowSession session = mSession; + MyWindow window = mWindow; + if (session == null || window == null) { + // Guess we got detached, that sucks + return; + } + if (mRTLastReportedPosition.left == left + && mRTLastReportedPosition.top == top + && mRTLastReportedPosition.right == right + && mRTLastReportedPosition.bottom == bottom) { + return; + } + try { + if (DEBUG) { + Log.d(TAG, String.format("updateWindowPosition RT, frameNr = %d, " + + "postion = [%d, %d, %d, %d]", frameNumber, left, top, + right, bottom)); } + // Just using mRTLastReportedPosition as a dummy rect here + session.repositionChild(window, left, top, right, bottom, frameNumber, + mRTLastReportedPosition); + // Now overwrite mRTLastReportedPosition with our values + mRTLastReportedPosition.set(left, top, right, bottom); + } catch (RemoteException ex) { + Log.e(TAG, "Exception from repositionChild", ex); } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 4a0a0b0dbeb7..127157b11a91 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4506,9 +4506,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } break; case R.styleable.View_pointerShape: - final int pointerShape = a.getInt(attr, PointerIcon.STYLE_NOT_SPECIFIED); - if (pointerShape != PointerIcon.STYLE_NOT_SPECIFIED) { - setPointerIcon(PointerIcon.getSystemIcon(context, pointerShape)); + final int resourceId = a.getResourceId(attr, 0); + if (resourceId != 0) { + setPointerIcon(PointerIcon.loadCustomIcon( + context.getResources(), resourceId)); + } else { + final int pointerShape = a.getInt(attr, PointerIcon.STYLE_NOT_SPECIFIED); + if (pointerShape != PointerIcon.STYLE_NOT_SPECIFIED) { + setPointerIcon(PointerIcon.getSystemIcon(context, pointerShape)); + } } break; } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 98e32891e033..96853e0fa775 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1811,7 +1811,9 @@ public final class ViewRootImpl implements ViewParent, final boolean dragResizing = freeformResizing || dockedResizing; if (mDragResizing != dragResizing) { if (dragResizing) { - startDragResizing(mPendingBackDropFrame); + startDragResizing(mPendingBackDropFrame, + mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets, + mPendingStableInsets); mResizeMode = freeformResizing ? RESIZE_MODE_FREEFORM : RESIZE_MODE_DOCKED_DIVIDER; @@ -5845,9 +5847,11 @@ public final class ViewRootImpl implements ViewParent, // Tell all listeners that we are resizing the window so that the chrome can get // updated as fast as possible on a separate thread, if (mDragResizing) { + boolean fullscreen = frame.equals(backDropFrame); synchronized (mWindowCallbacks) { for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { - mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame); + mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen, + visibleInsets, stableInsets); } } } @@ -6815,20 +6819,6 @@ public final class ViewRootImpl implements ViewParent, } } - long getNextFrameNumber() { - long frameNumber = -1; - if (mSurfaceHolder != null) { - mSurfaceHolder.mSurfaceLock.lock(); - } - if (mSurface.isValid()) { - frameNumber = mSurface.getNextFrameNumber(); - } - if (mSurfaceHolder != null) { - mSurfaceHolder.mSurfaceLock.unlock(); - } - return frameNumber; - } - class TakenSurfaceHolder extends BaseSurfaceHolder { @Override public boolean onAllowLockCanvas() { @@ -7060,12 +7050,14 @@ public final class ViewRootImpl implements ViewParent, /** * Start a drag resizing which will inform all listeners that a window resize is taking place. */ - private void startDragResizing(Rect initialBounds) { + private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets, + Rect stableInsets) { if (!mDragResizing) { mDragResizing = true; synchronized (mWindowCallbacks) { for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { - mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds); + mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen, + systemInsets, stableInsets); } } mFullRedrawNeeded = true; diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java index def02365dfed..d2bfca7e1c30 100644 --- a/core/java/android/view/WindowCallbacks.java +++ b/core/java/android/view/WindowCallbacks.java @@ -28,20 +28,30 @@ import android.graphics.Rect; public interface WindowCallbacks { /** * Called by the system when the window got changed by the user, before the layouter got called. - * It can be used to perform a "quick and dirty" resize which should never take more then 4ms to - * complete. + * It also gets called when the insets changed, or when the window switched between a fullscreen + * layout or a non-fullscreen layout. It can be used to perform a "quick and dirty" resize which + * should never take more then 4ms to complete. * * <p>At the time the layouting has not happened yet. * * @param newBounds The new window frame bounds. + * @param fullscreen Whether the window is currently drawing in fullscreen. + * @param systemInsets The current visible system insets for the window. + * @param stableInsets The stable insets for the window. */ - void onWindowSizeIsChanging(Rect newBounds); + void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets, + Rect stableInsets); /** * Called when a drag resize starts. + * * @param initialBounds The initial bounds where the window will be. + * @param fullscreen Whether the window is currently drawing in fullscreen. + * @param systemInsets The current visible system insets for the window. + * @param stableInsets The stable insets for the window. */ - void onWindowDragResizeStart(Rect initialBounds); + void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets, + Rect stableInsets); /** * Called when a drag resize ends. diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java index 89b1eb933025..c22d60d94818 100644 --- a/core/java/android/view/WindowManagerInternal.java +++ b/core/java/android/view/WindowManagerInternal.java @@ -268,4 +268,9 @@ public abstract class WindowManagerInternal { /** Returns true if the stack with the input Id is currently visible. */ public abstract boolean isStackVisible(int stackId); + + /** + * @return True if and only if the docked divider is currently in resize mode. + */ + public abstract boolean isDockedDividerResizing(); } diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 4ca8971b34ab..9a6859387bdf 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -955,7 +955,7 @@ public abstract class AbsSeekBar extends ProgressBar { if (!canUserSetProgress()) { return false; } - int increment = Math.max(1, Math.round((float) getMax() / 5)); + int increment = Math.max(1, Math.round((float) getMax() / 20)); if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) { increment = -increment; } diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 6e90baf26fa2..f601f7df1fa8 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -392,6 +392,26 @@ public class ImageView extends View { return mDrawable; } + private class ImageDrawableCallback implements Runnable { + + private final Drawable drawable; + private final Uri uri; + private final int resource; + + ImageDrawableCallback(Drawable drawable, Uri uri, int resource) { + this.drawable = drawable; + this.uri = uri; + this.resource = resource; + } + + @Override + public void run() { + setImageDrawable(drawable); + mUri = uri; + mResource = resource; + } + } + /** * Sets a drawable as the content of this ImageView. * @@ -405,7 +425,7 @@ public class ImageView extends View { * * @attr ref android.R.styleable#ImageView_src */ - @android.view.RemotableViewMethod + @android.view.RemotableViewMethod(asyncImpl="setImageResourceAsync") public void setImageResource(@DrawableRes int resId) { // The resource configuration may have changed, so we should always // try to load the resource even if the resId hasn't changed. @@ -424,6 +444,11 @@ public class ImageView extends View { invalidate(); } + /** @hide **/ + public Runnable setImageResourceAsync(@DrawableRes int resId) { + return new ImageDrawableCallback(getContext().getDrawable(resId), null, resId); + } + /** * Sets the content of this ImageView to the specified Uri. * @@ -435,7 +460,7 @@ public class ImageView extends View { * * @param uri the Uri of an image, or {@code null} to clear the content */ - @android.view.RemotableViewMethod + @android.view.RemotableViewMethod(asyncImpl="setImageURIAsync") public void setImageURI(@Nullable Uri uri) { if (mResource != 0 || (mUri != uri && (uri == null || mUri == null || !uri.equals(mUri)))) { updateDrawable(null); @@ -454,6 +479,19 @@ public class ImageView extends View { } } + /** @hide **/ + public Runnable setImageURIAsync(@Nullable Uri uri) { + if (mResource != 0 || (mUri != uri && (uri == null || mUri == null || !uri.equals(mUri)))) { + Drawable d = uri == null ? null : getDrawableFromUri(uri); + if (d == null) { + // Do not set the URI if the drawable couldn't be loaded. + uri = null; + } + return new ImageDrawableCallback(d, uri, 0); + } + return null; + } + /** * Sets a drawable as the content of this ImageView. * @@ -490,11 +528,16 @@ public class ImageView extends View { * @param icon an Icon holding the desired image, or {@code null} to clear * the content */ - @android.view.RemotableViewMethod + @android.view.RemotableViewMethod(asyncImpl="setImageIconAsync") public void setImageIcon(@Nullable Icon icon) { setImageDrawable(icon == null ? null : icon.loadDrawable(mContext)); } + /** @hide **/ + public Runnable setImageIconAsync(@Nullable Icon icon) { + return new ImageDrawableCallback(icon == null ? null : icon.loadDrawable(mContext), null, 0); + } + /** * Applies a tint to the image drawable. Does not modify the current tint * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. @@ -786,8 +829,7 @@ public class ImageView extends View { return; } - final Resources res = getResources(); - if (res == null) { + if (getResources() == null) { return; } @@ -802,37 +844,7 @@ public class ImageView extends View { mUri = null; } } else if (mUri != null) { - final String scheme = mUri.getScheme(); - if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) { - try { - // Load drawable through Resources, to get the source density information - ContentResolver.OpenResourceIdResult r = - mContext.getContentResolver().getResourceId(mUri); - d = r.r.getDrawable(r.id, mContext.getTheme()); - } catch (Exception e) { - Log.w(LOG_TAG, "Unable to open content: " + mUri, e); - } - } else if (ContentResolver.SCHEME_CONTENT.equals(scheme) - || ContentResolver.SCHEME_FILE.equals(scheme)) { - InputStream stream = null; - try { - stream = mContext.getContentResolver().openInputStream(mUri); - d = Drawable.createFromResourceStream( - mUseCorrectStreamDensity ? res : null, null, stream, null); - } catch (Exception e) { - Log.w(LOG_TAG, "Unable to open content: " + mUri, e); - } finally { - if (stream != null) { - try { - stream.close(); - } catch (IOException e) { - Log.w(LOG_TAG, "Unable to close content: " + mUri, e); - } - } - } - } else { - d = Drawable.createFromPath(mUri.toString()); - } + d = getDrawableFromUri(mUri); if (d == null) { Log.w(LOG_TAG, "resolveUri failed on bad bitmap uri: " + mUri); @@ -846,6 +858,41 @@ public class ImageView extends View { updateDrawable(d); } + private Drawable getDrawableFromUri(Uri uri) { + final String scheme = uri.getScheme(); + if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) { + try { + // Load drawable through Resources, to get the source density information + ContentResolver.OpenResourceIdResult r = + mContext.getContentResolver().getResourceId(uri); + return r.r.getDrawable(r.id, mContext.getTheme()); + } catch (Exception e) { + Log.w(LOG_TAG, "Unable to open content: " + uri, e); + } + } else if (ContentResolver.SCHEME_CONTENT.equals(scheme) + || ContentResolver.SCHEME_FILE.equals(scheme)) { + InputStream stream = null; + try { + stream = mContext.getContentResolver().openInputStream(uri); + return Drawable.createFromResourceStream( + mUseCorrectStreamDensity ? getResources() : null, null, stream, null); + } catch (Exception e) { + Log.w(LOG_TAG, "Unable to open content: " + uri, e); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + Log.w(LOG_TAG, "Unable to close content: " + uri, e); + } + } + } + } else { + return Drawable.createFromPath(uri.toString()); + } + return null; + } + @Override public int[] onCreateDrawableState(int extraSpace) { if (mState == null) { diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 584df08412f2..8fa71a21cd4a 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -43,6 +43,7 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; +import android.view.View.OnAttachStateChangeListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.ViewParent; @@ -164,7 +165,20 @@ public class PopupWindow { com.android.internal.R.attr.state_above_anchor }; + private final OnAttachStateChangeListener mOnAnchorRootDetachedListener = + new OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) {} + + @Override + public void onViewDetachedFromWindow(View v) { + mIsAnchorRootAttached = false; + } + }; + private WeakReference<View> mAnchor; + private WeakReference<View> mAnchorRoot; + private boolean mIsAnchorRootAttached; private final OnScrollChangedListener mOnScrollChangedListener = new OnScrollChangedListener() { @Override @@ -1037,7 +1051,7 @@ public class PopupWindow { TransitionManager.endTransitions(mDecorView); - unregisterForScrollChanged(); + unregisterForViewTreeChanges(); mIsShowing = true; mIsDropdown = false; @@ -1120,7 +1134,7 @@ public class PopupWindow { TransitionManager.endTransitions(mDecorView); - registerForScrollChanged(anchor, xoff, yoff, gravity); + registerForViewTreeChanges(anchor, xoff, yoff, gravity); mIsShowing = true; mIsDropdown = true; @@ -1633,14 +1647,23 @@ public class PopupWindow { mIsShowing = false; mIsTransitioningToDismiss = true; + // This method may be called as part of window detachment, in which + // case the anchor view (and its root) will still return true from + // isAttachedToWindow() during execution of this method; however, we + // can expect the OnAttachStateChangeListener to have been called prior + // to executing this method, so we can rely on that instead. final Transition exitTransition = mExitTransition; - if (exitTransition != null && decorView.isLaidOut()) { + if (!mIsAnchorRootAttached && exitTransition != null && decorView.isLaidOut()) { // The decor view is non-interactive during exit transitions. final LayoutParams p = (LayoutParams) decorView.getLayoutParams(); p.flags |= LayoutParams.FLAG_NOT_TOUCHABLE; p.flags |= LayoutParams.FLAG_NOT_FOCUSABLE; mWindowManager.updateViewLayout(decorView, p); + // Once we start dismissing the decor view, all state (including + // the anchor root) needs to be moved to the decor view since we + // may open another popup while it's busy exiting. + final View anchorRoot = mAnchorRoot != null ? mAnchorRoot.get() : null; final Rect epicenter = getTransitionEpicenter(); exitTransition.setEpicenterCallback(new EpicenterCallback() { @Override @@ -1648,18 +1671,19 @@ public class PopupWindow { return epicenter; } }); - decorView.startExitTransition(exitTransition, new TransitionListenerAdapter() { - @Override - public void onTransitionEnd(Transition transition) { - dismissImmediate(decorView, contentHolder, contentView); - } - }); + decorView.startExitTransition(exitTransition, anchorRoot, + new TransitionListenerAdapter() { + @Override + public void onTransitionEnd(Transition transition) { + dismissImmediate(decorView, contentHolder, contentView); + } + }); } else { dismissImmediate(decorView, contentHolder, contentView); } // Clears the anchor view. - unregisterForScrollChanged(); + unregisterForViewTreeChanges(); if (mOnDismissListener != null) { mOnDismissListener.onDismiss(); @@ -1925,7 +1949,7 @@ public class PopupWindow { final WeakReference<View> oldAnchor = mAnchor; final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff); if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) { - registerForScrollChanged(anchor, xoff, yoff, mAnchoredGravity); + registerForViewTreeChanges(anchor, xoff, yoff, mAnchoredGravity); } else if (needsUpdate) { // No need to register again if this is a DropDown, showAsDropDown already did. mAnchorXoff = xoff; @@ -1969,27 +1993,38 @@ public class PopupWindow { public void onDismiss(); } - private void unregisterForScrollChanged() { - final WeakReference<View> anchorRef = mAnchor; - final View anchor = anchorRef == null ? null : anchorRef.get(); + private void unregisterForViewTreeChanges() { + final View anchor = mAnchor != null ? mAnchor.get() : null; if (anchor != null) { final ViewTreeObserver vto = anchor.getViewTreeObserver(); vto.removeOnScrollChangedListener(mOnScrollChangedListener); } + final View anchorRoot = mAnchorRoot != null ? mAnchorRoot.get() : null; + if (anchorRoot != null) { + anchorRoot.removeOnAttachStateChangeListener(mOnAnchorRootDetachedListener); + } + mAnchor = null; + mAnchorRoot = null; + mIsAnchorRootAttached = false; } - private void registerForScrollChanged(View anchor, int xoff, int yoff, int gravity) { - unregisterForScrollChanged(); - - mAnchor = new WeakReference<>(anchor); + private void registerForViewTreeChanges(View anchor, int xoff, int yoff, int gravity) { + unregisterForViewTreeChanges(); final ViewTreeObserver vto = anchor.getViewTreeObserver(); if (vto != null) { vto.addOnScrollChangedListener(mOnScrollChangedListener); } + final View anchorRoot = anchor.getRootView(); + anchorRoot.addOnAttachStateChangeListener(mOnAnchorRootDetachedListener); + + mAnchor = new WeakReference<>(anchor); + mAnchorRoot = new WeakReference<>(anchorRoot); + mIsAnchorRootAttached = anchorRoot.isAttachedToWindow(); + mAnchorXoff = xoff; mAnchorYoff = yoff; mAnchoredGravity = gravity; @@ -2109,16 +2144,23 @@ public class PopupWindow { * its {@code onTransitionEnd} method called even if the transition * never starts; however, it may be called with a {@code null} argument. */ - public void startExitTransition(Transition transition, final TransitionListener listener) { + public void startExitTransition(Transition transition, final View anchorRoot, + final TransitionListener listener) { if (transition == null) { return; } + // The anchor view's window may go away while we're executing our + // transition, in which case we need to end the transition + // immediately and execute the listener to remove the popup. + anchorRoot.addOnAttachStateChangeListener(mOnAnchorRootDetachedListener); + // The exit listener MUST be called for cleanup, even if the // transition never starts or ends. Stash it for later. mPendingExitListener = new TransitionListenerAdapter() { @Override public void onTransitionEnd(Transition transition) { + anchorRoot.removeOnAttachStateChangeListener(mOnAnchorRootDetachedListener); listener.onTransitionEnd(transition); // The listener was called. Our job here is done. @@ -2153,6 +2195,19 @@ public class PopupWindow { mPendingExitListener.onTransitionEnd(null); } } + + private final OnAttachStateChangeListener mOnAnchorRootDetachedListener = + new OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) {} + + @Override + public void onViewDetachedFromWindow(View v) { + v.removeOnAttachStateChangeListener(this); + + TransitionManager.endTransitions(PopupDecorView.this); + } + }; } private class PopupBackgroundView extends FrameLayout { diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 0dd803a23d30..dee25d35364c 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -39,8 +39,10 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.net.Uri; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Parcel; import android.os.Parcelable; import android.os.StrictMode; @@ -66,6 +68,7 @@ import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.Executor; /** * A class that describes a view hierarchy that can be displayed in @@ -146,6 +149,8 @@ public class RemoteViews implements Parcelable, Filter { private static final Object[] sMethodsLock = new Object[0]; private static final ArrayMap<Class<? extends View>, ArrayMap<MutablePair<String, Class<?>>, Method>> sMethods = new ArrayMap<Class<? extends View>, ArrayMap<MutablePair<String, Class<?>>, Method>>(); + private static final ArrayMap<Method, Method> sAsyncMethods = new ArrayMap<>(); + private static final ThreadLocal<Object[]> sInvokeArgsTls = new ThreadLocal<Object[]>() { @Override protected Object[] initialValue() { @@ -293,10 +298,40 @@ public class RemoteViews implements Parcelable, Filter { return (getActionName() + viewId); } + /** + * This is called on the background thread. It should perform any non-ui computations + * and return the final action which will run on the UI thread. + * Override this if some of the tasks can be performed async. + */ + public Action initActionAsync(ViewTree root, ViewGroup rootParent, OnClickHandler handler) { + return this; + } + int viewId; } /** + * Action class used during async inflation of RemoteViews. Subclasses are not parcelable. + */ + private static abstract class RuntimeAction extends Action { + @Override + public final String getActionName() { + return "RuntimeAction"; + } + + @Override + public final void writeToParcel(Parcel dest, int flags) { + throw new UnsupportedOperationException(); + } + } + + // Constant used during async execution. It is not parcelable. + private static final Action ACTION_NOOP = new RuntimeAction() { + @Override + public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { } + }; + + /** * Merges the passed RemoteViews actions with this RemoteViews actions according to * action-specific merge rules. * @@ -810,6 +845,36 @@ public class RemoteViews implements Parcelable, Filter { return method; } + /** + * @return the async implementation of the provided method. + */ + private Method getAsyncMethod(Method method) { + synchronized (sAsyncMethods) { + int valueIndex = sAsyncMethods.indexOfKey(method); + if (valueIndex >= 0) { + return sAsyncMethods.valueAt(valueIndex); + } + + RemotableViewMethod annotation = method.getAnnotation(RemotableViewMethod.class); + Method asyncMethod = null; + if (!annotation.asyncImpl().isEmpty()) { + try { + asyncMethod = method.getDeclaringClass() + .getMethod(annotation.asyncImpl(), method.getParameterTypes()); + if (!asyncMethod.getReturnType().equals(Runnable.class)) { + throw new ActionException("Async implementation for " + method.getName() + + " does not return a Runnable"); + } + } catch (NoSuchMethodException ex) { + throw new ActionException("Async implementation declared but not defined for " + + method.getName()); + } + } + sAsyncMethods.put(method, asyncMethod); + return asyncMethod; + } + } + private static String getParameters(Class<?> paramType) { if (paramType == null) return "()"; return "(" + paramType + ")"; @@ -1324,6 +1389,37 @@ public class RemoteViews implements Parcelable, Filter { } } + @Override + public Action initActionAsync(ViewTree root, ViewGroup rootParent, OnClickHandler handler) { + final View view = root.findViewById(viewId); + if (view == null) return ACTION_NOOP; + + Class<?> param = getParameterType(); + if (param == null) { + throw new ActionException("bad type: " + this.type); + } + + try { + Method method = getMethod(view, this.methodName, param); + Method asyncMethod = getAsyncMethod(method); + + if (asyncMethod != null) { + Runnable endAction = (Runnable) asyncMethod.invoke(view, wrapArg(this.value)); + if (endAction == null) { + return ACTION_NOOP; + } else { + return new RunnableAction(endAction); + } + } + } catch (ActionException e) { + throw e; + } catch (Exception ex) { + throw new ActionException(ex); + } + + return this; + } + public int mergeBehavior() { // smoothScrollBy is cumulative, everything else overwites. if (methodName.equals("smoothScrollBy")) { @@ -1340,6 +1436,22 @@ public class RemoteViews implements Parcelable, Filter { } } + /** + * This is only used for async execution of actions and it not parcelable. + */ + private static final class RunnableAction extends RuntimeAction { + private final Runnable mRunnable; + + RunnableAction(Runnable r) { + mRunnable = r; + } + + @Override + public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { + mRunnable.run(); + } + } + private void configureRemoteViewsAsChild(RemoteViews rv) { mBitmapCache.assimilate(rv.mBitmapCache); rv.setBitmapCache(mBitmapCache); @@ -1401,6 +1513,43 @@ public class RemoteViews implements Parcelable, Filter { } @Override + public Action initActionAsync(ViewTree root, ViewGroup rootParent, OnClickHandler handler) { + // In the async implementation, update the view tree so that subsequent calls to + // findViewById return the currect view. + root.createTree(); + ViewTree target = root.findViewTreeById(viewId); + if ((target == null) || !(target.mRoot instanceof ViewGroup)) { + return ACTION_NOOP; + } + if (nestedViews == null) { + // Clear all children when nested views omitted + target.mChildren = null; + return this; + } else { + // Inflate nested views and perform all the async tasks for the child remoteView. + final Context context = root.mRoot.getContext(); + final AsyncApplyTask task = nestedViews.getAsyncApplyTask( + context, (ViewGroup) target.mRoot, null, handler); + final ViewTree tree = task.doInBackground(); + + // Update the global view tree, so that next call to findViewTreeById + // goes through the subtree as well. + target.addChild(tree); + + return new RuntimeAction() { + + @Override + public void apply(View root, ViewGroup rootParent, OnClickHandler handler) throws ActionException { + // This view will exist as we have already made sure + final ViewGroup target = (ViewGroup) root.findViewById(viewId); + task.onPostExecute(tree); + target.addView(task.mResult); + } + }; + } + } + + @Override public void updateMemoryUsageEstimate(MemoryUsageCounter counter) { if (nestedViews != null) { counter.increment(nestedViews.estimateMemoryUsage()); @@ -1520,7 +1669,13 @@ public class RemoteViews implements Parcelable, Filter { public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { final TextView target = (TextView) root.findViewById(viewId); if (target == null) return; - if (useIcons) { + if (drawablesLoaded) { + if (isRelative) { + target.setCompoundDrawablesRelativeWithIntrinsicBounds(id1, id2, id3, id4); + } else { + target.setCompoundDrawablesWithIntrinsicBounds(id1, id2, id3, id4); + } + } else if (useIcons) { final Context ctx = target.getContext(); final Drawable id1 = i1 == null ? null : i1.loadDrawable(ctx); final Drawable id2 = i2 == null ? null : i2.loadDrawable(ctx); @@ -1540,6 +1695,33 @@ public class RemoteViews implements Parcelable, Filter { } } + @Override + public Action initActionAsync(ViewTree root, ViewGroup rootParent, OnClickHandler handler) { + final TextView target = (TextView) root.findViewById(viewId); + if (target == null) return ACTION_NOOP; + + TextViewDrawableAction copy = useIcons ? + new TextViewDrawableAction(viewId, isRelative, i1, i2, i3, i4) : + new TextViewDrawableAction(viewId, isRelative, d1, d2, d3, d4); + + // Load the drawables on the background thread. + copy.drawablesLoaded = true; + final Context ctx = target.getContext(); + + if (useIcons) { + copy.id1 = i1 == null ? null : i1.loadDrawable(ctx); + copy.id2 = i2 == null ? null : i2.loadDrawable(ctx); + copy.id3 = i3 == null ? null : i3.loadDrawable(ctx); + copy.id4 = i4 == null ? null : i4.loadDrawable(ctx); + } else { + copy.id1 = d1 == 0 ? null : ctx.getDrawable(d1); + copy.id2 = d2 == 0 ? null : ctx.getDrawable(d2); + copy.id3 = d3 == 0 ? null : ctx.getDrawable(d3); + copy.id4 = d4 == 0 ? null : ctx.getDrawable(d4); + } + return copy; + } + public String getActionName() { return "TextViewDrawableAction"; } @@ -1549,6 +1731,9 @@ public class RemoteViews implements Parcelable, Filter { int d1, d2, d3, d4; Icon i1, i2, i3, i4; + boolean drawablesLoaded = false; + Drawable id1, id2, id3, id4; + public final static int TAG = 11; } @@ -2852,7 +3037,15 @@ public class RemoteViews implements Parcelable, Filter { public View apply(Context context, ViewGroup parent, OnClickHandler handler) { RemoteViews rvToApply = getRemoteViewsToApply(context); - View result; + View result = inflateView(context, rvToApply, parent); + loadTransitionOverride(context, handler); + + rvToApply.performApply(result, parent, handler); + + return result; + } + + private View inflateView(Context context, RemoteViews rv, ViewGroup parent) { // RemoteViews may be built by an application installed in another // user. So build a context that loads resources from that user but // still returns the current users userId so settings like data / time formats @@ -2880,13 +3073,7 @@ public class RemoteViews implements Parcelable, Filter { // we don't add a filter to the static version returned by getSystemService. inflater = inflater.cloneInContext(inflationContext); inflater.setFilter(this); - result = inflater.inflate(rvToApply.getLayoutId(), parent, false); - - loadTransitionOverride(context, handler); - - rvToApply.performApply(result, parent, handler); - - return result; + return inflater.inflate(rv.getLayoutId(), parent, false); } private static void loadTransitionOverride(Context context, @@ -2908,6 +3095,143 @@ public class RemoteViews implements Parcelable, Filter { } /** + * Implement this interface to receive a callback when + * {@link #applyAsync} or {@link #reapplyAsync} is finished. + * @hide + */ + public interface OnViewAppliedListener { + void onViewApplied(View v); + + void onError(Exception e); + } + + /** + * Applies the views asynchronously, moving as much of the task on the background + * thread as possible. + * + * @see {@link #apply(Context, ViewGroup)} + * @param context Default context to use + * @param parent Parent that the resulting view hierarchy will be attached to. This method + * does <strong>not</strong> attach the hierarchy. The caller should do so when appropriate. + * @param listener the callback to run when all actions have been applied. May be null. + * @param executor The executor to use. If null {@link AsyncTask#THREAD_POOL_EXECUTOR} is used. + * @return CancellationSignal + * @hide + */ + public CancellationSignal applyAsync( + Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener) { + return applyAsync(context, parent, executor, listener, null); + } + + private CancellationSignal startTaskOnExecutor(AsyncApplyTask task, Executor executor) { + CancellationSignal cancelSignal = new CancellationSignal(); + cancelSignal.setOnCancelListener(task); + + task.executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor); + return cancelSignal; + } + + /** @hide */ + public CancellationSignal applyAsync(Context context, ViewGroup parent, + Executor executor, OnViewAppliedListener listener, OnClickHandler handler) { + return startTaskOnExecutor(getAsyncApplyTask(context, parent, listener, handler), executor); + } + + private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent, + OnViewAppliedListener listener, OnClickHandler handler) { + return new AsyncApplyTask(getRemoteViewsToApply(context), parent, context, listener, + handler, null); + } + + private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree> + implements CancellationSignal.OnCancelListener { + final RemoteViews mRV; + final ViewGroup mParent; + final Context mContext; + final OnViewAppliedListener mListener; + final OnClickHandler mHandler; + + private View mResult; + private ViewTree mTree; + private Action[] mActions; + private Exception mError; + + private AsyncApplyTask( + RemoteViews rv, ViewGroup parent, Context context, OnViewAppliedListener listener, + OnClickHandler handler, View result) { + mRV = rv; + mParent = parent; + mContext = context; + mListener = listener; + mHandler = handler; + + mResult = result; + loadTransitionOverride(context, handler); + } + + @Override + protected ViewTree doInBackground(Void... params) { + try { + if (mResult == null) { + mResult = inflateView(mContext, mRV, mParent); + } + + mTree = new ViewTree(mResult); + if (mRV.mActions != null) { + int count = mRV.mActions.size(); + mActions = new Action[count]; + for (int i = 0; i < count && !isCancelled(); i++) { + // TODO: check if isCanclled in nested views. + mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler); + } + } else { + mActions = null; + } + return mTree; + } catch (Exception e) { + mError = e; + return null; + } + } + + @Override + protected void onPostExecute(ViewTree viewTree) { + if (mError == null) { + try { + if (mActions != null) { + OnClickHandler handler = mHandler == null + ? DEFAULT_ON_CLICK_HANDLER : mHandler; + for (Action a : mActions) { + a.apply(viewTree.mRoot, mParent, handler); + } + } + } catch (Exception e) { + mError = e; + } + } + + if (mListener != null) { + if (mError != null) { + mListener.onError(mError); + } else { + mListener.onViewApplied(viewTree.mRoot); + } + } else if (mError != null) { + if (mError instanceof ActionException) { + throw (ActionException) mError; + } else { + throw new ActionException(mError); + } + } + } + + @Override + public void onCancel() { + cancel(true); + } + } + + /** * Applies all of the actions to the provided view. * * <p><strong>Caller beware: this may throw</strong> @@ -2936,6 +3260,43 @@ public class RemoteViews implements Parcelable, Filter { rvToApply.performApply(v, (ViewGroup) v.getParent(), handler); } + /** + * Applies all the actions to the provided view, moving as much of the task on the background + * thread as possible. + * + * @see {@link #reapply(Context, View)} + * @param context Default context to use + * @param v The view to apply the actions to. This should be the result of + * the {@link #apply(Context,ViewGroup)} call. + * @param listener the callback to run when all actions have been applied. May be null. + * @param executor The executor to use. If null {@link AsyncTask#THREAD_POOL_EXECUTOR} is used + * @return CancellationSignal + * @hide + */ + public CancellationSignal reapplyAsync( + Context context, View v, Executor executor, OnViewAppliedListener listener) { + return reapplyAsync(context, v, executor, listener, null); + } + + /** @hide */ + public CancellationSignal reapplyAsync(Context context, View v, Executor executor, + OnViewAppliedListener listener, OnClickHandler handler) { + RemoteViews rvToApply = getRemoteViewsToApply(context); + + // In the case that a view has this RemoteViews applied in one orientation, is persisted + // across orientation change, and has the RemoteViews re-applied in the new orientation, + // we throw an exception, since the layouts may be completely unrelated. + if (hasLandscapeAndPortraitLayouts()) { + if (v.getId() != rvToApply.getLayoutId()) { + throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" + + " that does not share the same root layout id."); + } + } + + return startTaskOnExecutor(new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(), + context, listener, handler, v), executor); + } + private void performApply(View v, ViewGroup parent, OnClickHandler handler) { if (mActions != null) { handler = handler == null ? DEFAULT_ON_CLICK_HANDLER : handler; @@ -3058,4 +3419,90 @@ public class RemoteViews implements Parcelable, Filter { return new RemoteViews[size]; } }; + + /** + * A representation of the view hierarchy. Only views which have a valid ID are added + * and can be searched. + */ + private static class ViewTree { + private final View mRoot; + + private ArrayList<ViewTree> mChildren; + + private ViewTree(View root) { + mRoot = root; + } + + public void createTree() { + if (mChildren != null) { + return; + } + + mChildren = new ArrayList<>(); + if (mRoot instanceof ViewGroup && mRoot.isRootNamespace()) { + ViewGroup vg = (ViewGroup) mRoot; + int count = vg.getChildCount(); + for (int i = 0; i < count; i++) { + addViewChild(vg.getChildAt(i)); + } + } + } + + public ViewTree findViewTreeById(int id) { + if (mRoot.getId() == id) { + return this; + } + if (mChildren == null) { + return null; + } + for (ViewTree tree : mChildren) { + ViewTree result = tree.findViewTreeById(id); + if (result != null) { + return result; + } + } + return null; + } + + public View findViewById(int id) { + if (mChildren == null) { + return mRoot.findViewById(id); + } + ViewTree tree = findViewTreeById(id); + return tree == null ? null : tree.mRoot; + } + + public void addChild(ViewTree child) { + if (mChildren == null) { + mChildren = new ArrayList<>(); + } + child.createTree(); + mChildren.add(child); + } + + private void addViewChild(View v) { + final ViewTree target; + + // If the view has a valid id, i.e., if can be found using findViewById, add it to the + // tree, otherwise skip this view and add its children instead. + if (v.getId() != 0) { + ViewTree tree = new ViewTree(v); + mChildren.add(tree); + target = tree; + } else { + target = this; + } + + if (v instanceof ViewGroup && v.isRootNamespace()) { + if (target.mChildren == null) { + target.mChildren = new ArrayList<>(); + ViewGroup vg = (ViewGroup) v; + int count = vg.getChildCount(); + for (int i = 0; i < count; i++) { + target.addViewChild(vg.getChildAt(i)); + } + } + } + } + } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index c626af65016c..712a04bf6fae 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -115,7 +115,6 @@ import android.view.ContextMenu; import android.view.DragEvent; import android.view.Gravity; import android.view.HapticFeedbackConstants; -import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; @@ -395,6 +394,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * @return {@code true} if this object contains metadata that needs to + * be retained, {@code false} otherwise + */ + public boolean hasMetadata() { + return mDrawablePadding != 0 || mHasTintMode || mHasTint; + } + + /** * Updates the list of displayed drawables to account for the current * layout direction. * @@ -2174,7 +2181,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (!drawables) { // Clearing drawables... can we free the data structure? if (dr != null) { - if (dr.mDrawablePadding == 0) { + if (!dr.hasMetadata()) { mDrawables = null; } else { // We need to retain the last set padding, so just clear @@ -2377,7 +2384,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (!drawables) { // Clearing drawables... can we free the data structure? if (dr != null) { - if (dr.mDrawablePadding == 0) { + if (!dr.hasMetadata()) { mDrawables = null; } else { // We need to retain the last set padding, so just clear diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index cf13a13cafb7..b0fb93b89052 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -761,6 +761,7 @@ public class ChooserActivity extends ResolverActivity { public static final int TARGET_STANDARD = 2; private static final int MAX_SERVICE_TARGETS = 8; + private static final int MAX_TARGETS_PER_SERVICE = 4; private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>(); private final List<TargetInfo> mCallerTargets = new ArrayList<>(); @@ -925,7 +926,7 @@ public class ChooserActivity extends ResolverActivity { final float parentScore = getScore(origTarget); Collections.sort(targets, mBaseTargetComparator); float lastScore = 0; - for (int i = 0, N = targets.size(); i < N; i++) { + for (int i = 0, N = Math.min(targets.size(), MAX_TARGETS_PER_SERVICE); i < N; i++) { final ChooserTarget target = targets.get(i); float targetScore = target.getScore(); targetScore *= parentScore; diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index dbec7405fe49..015e60dd2a7d 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -85,8 +85,10 @@ public class IntentForwarderActivity extends Activity { int callingUserId = getUserId(); if (canForward(newIntent, targetUserId)) { - if (newIntent.getAction().equals(Intent.ACTION_CHOOSER)) { + if (Intent.ACTION_CHOOSER.equals(newIntent.getAction())) { Intent innerIntent = (Intent) newIntent.getParcelableExtra(Intent.EXTRA_INTENT); + // At this point, innerIntent is not null. Otherwise, canForward would have returned + // false. innerIntent.prepareToLeaveUser(callingUserId); } else { newIntent.prepareToLeaveUser(callingUserId); @@ -124,7 +126,7 @@ public class IntentForwarderActivity extends Activity { Toast.makeText(this, getString(userMessageId), Toast.LENGTH_LONG).show(); } } else { - Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user " + Slog.wtf(TAG, "the intent: " + newIntent + " cannot be forwarded from user " + callingUserId + " to user " + targetUserId); } finish(); @@ -132,7 +134,7 @@ public class IntentForwarderActivity extends Activity { boolean canForward(Intent intent, int targetUserId) { IPackageManager ipm = AppGlobals.getPackageManager(); - if (intent.getAction().equals(Intent.ACTION_CHOOSER)) { + if (Intent.ACTION_CHOOSER.equals(intent.getAction())) { // The EXTRA_INITIAL_INTENTS may not be allowed to be forwarded. if (intent.hasExtra(Intent.EXTRA_INITIAL_INTENTS)) { Slog.wtf(TAG, "An chooser intent with extra initial intents cannot be forwarded to" @@ -145,6 +147,11 @@ public class IntentForwarderActivity extends Activity { return false; } intent = (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT); + if (intent == null) { + Slog.wtf(TAG, "Cannot forward a chooser intent with no extra " + + Intent.EXTRA_INTENT); + return false; + } } String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); if (intent.getSelector() != null) { diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java index 9a1788373534..956ee8c9242d 100644 --- a/core/java/com/android/internal/app/LocalePickerWithRegion.java +++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java @@ -138,22 +138,12 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O super.onCreate(savedInstanceState); setHasOptionsMenu(true); - Locale sortingLocale; - if (mCountryMode) { - if (mParentLocale == null) { - sortingLocale = Locale.getDefault(); - this.getActivity().setTitle(R.string.country_selection_title); - } else { - sortingLocale = mParentLocale.getLocale(); - this.getActivity().setTitle(mParentLocale.getFullNameNative()); - } - } else { - sortingLocale = Locale.getDefault(); - this.getActivity().setTitle(R.string.language_selection_title); - } + final Locale sortingLocale = (mCountryMode && mParentLocale != null) + ? mParentLocale.getLocale() + : Locale.getDefault(); mAdapter = new SuggestedLocaleAdapter(mLocaleList, mCountryMode); - LocaleHelper.LocaleInfoComparator comp = + final LocaleHelper.LocaleInfoComparator comp = new LocaleHelper.LocaleInfoComparator(sortingLocale); mAdapter.sort(comp); setListAdapter(mAdapter); @@ -173,6 +163,17 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O @Override public void onResume() { super.onResume(); + + if (mCountryMode) { + if (mParentLocale == null) { + this.getActivity().setTitle(R.string.country_selection_title); + } else { + this.getActivity().setTitle(mParentLocale.getFullNameNative()); + } + } else { + this.getActivity().setTitle(R.string.language_selection_title); + } + getListView().requestFocus(); } diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java index 0ae21c61112f..03a3a3821f6a 100644 --- a/core/java/com/android/internal/app/ResolverComparator.java +++ b/core/java/com/android/internal/app/ResolverComparator.java @@ -52,7 +52,7 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { private static final long RECENCY_TIME_PERIOD = 1000 * 60 * 60 * 12; - private static final float RECENCY_MULTIPLIER = 3.f; + private static final float RECENCY_MULTIPLIER = 2.f; private final Collator mCollator; private final boolean mHttp; diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java index 5047c4c11889..69311938c5ad 100644 --- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java +++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java @@ -24,7 +24,6 @@ import android.view.Choreographer; import android.view.DisplayListCanvas; import android.view.RenderNode; import android.view.ThreadedRenderer; -import android.view.View; /** * The thread which draws a fill in background while the app is resizing in areas where the app @@ -49,6 +48,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame private final Rect mOldTargetRect = new Rect(); private final Rect mNewTargetRect = new Rect(); + private Choreographer mChoreographer; // Cached size values from the last render for the case that the view hierarchy is gone @@ -66,15 +66,23 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame private Drawable mUserCaptionBackgroundDrawable; private Drawable mResizingBackgroundDrawable; private ColorDrawable mStatusBarColor; + private ColorDrawable mNavigationBarColor; + private boolean mOldFullscreen; + private boolean mFullscreen; + private final Rect mOldSystemInsets = new Rect(); + private final Rect mOldStableInsets = new Rect(); + private final Rect mSystemInsets = new Rect(); + private final Rect mStableInsets = new Rect(); public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds, Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable, - Drawable userCaptionBackgroundDrawable, int statusBarColor) { + Drawable userCaptionBackgroundDrawable, int statusBarColor, int navigationBarColor, + boolean fullscreen, Rect systemInsets, Rect stableInsets) { setName("ResizeFrame"); mRenderer = renderer; onResourcesLoaded(decorView, resizingBackgroundDrawable, captionBackgroundDrawable, - userCaptionBackgroundDrawable, statusBarColor); + userCaptionBackgroundDrawable, statusBarColor, navigationBarColor); // Create a render node for the content and frame backdrop // which can be resized independently from the content. @@ -84,8 +92,14 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame // Set the initial bounds and draw once so that we do not get a broken frame. mTargetRect.set(initialBounds); + mFullscreen = fullscreen; + mOldFullscreen = fullscreen; + mSystemInsets.set(systemInsets); + mStableInsets.set(stableInsets); + mOldSystemInsets.set(systemInsets); + mOldStableInsets.set(stableInsets); synchronized (this) { - changeWindowSizeLocked(initialBounds); + redrawLocked(initialBounds, fullscreen, mSystemInsets, mStableInsets); } // Kick off our draw thread. @@ -94,7 +108,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame void onResourcesLoaded(DecorView decorView, Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawableDrawable, Drawable userCaptionBackgroundDrawable, - int statusBarColor) { + int statusBarColor, int navigationBarColor) { mDecorView = decorView; mResizingBackgroundDrawable = resizingBackgroundDrawable; mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable; @@ -108,6 +122,12 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame } else { mStatusBarColor = null; } + if (navigationBarColor != 0) { + mNavigationBarColor = new ColorDrawable(navigationBarColor); + addSystemBarNodeIfNeeded(); + } else { + mNavigationBarColor = null; + } } private void addSystemBarNodeIfNeeded() { @@ -119,13 +139,22 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame } /** - * Call this function asynchronously when the window size has been changed. The change will - * be picked up once per frame and the frame will be re-rendered accordingly. + * Call this function asynchronously when the window size has been changed or when the insets + * have changed or whether window switched between a fullscreen or non-fullscreen layout. + * The change will be picked up once per frame and the frame will be re-rendered accordingly. + * * @param newTargetBounds The new target bounds. + * @param fullscreen Whether the window is currently drawing in fullscreen. + * @param systemInsets The current visible system insets for the window. + * @param stableInsets The stable insets for the window. */ - public void setTargetRect(Rect newTargetBounds) { + public void setTargetRect(Rect newTargetBounds, boolean fullscreen, Rect systemInsets, + Rect stableInsets) { synchronized (this) { + mFullscreen = fullscreen; mTargetRect.set(newTargetBounds); + mSystemInsets.set(systemInsets); + mStableInsets.set(stableInsets); // Notify of a bounds change. pingRenderLocked(); } @@ -204,16 +233,23 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame return; } mNewTargetRect.set(mTargetRect); - if (!mNewTargetRect.equals(mOldTargetRect) || mReportNextDraw) { + if (!mNewTargetRect.equals(mOldTargetRect) + || mOldFullscreen != mFullscreen + || !mStableInsets.equals(mOldStableInsets) + || !mSystemInsets.equals(mOldSystemInsets) + || mReportNextDraw) { + mOldFullscreen = mFullscreen; mOldTargetRect.set(mNewTargetRect); - changeWindowSizeLocked(mNewTargetRect); + mOldSystemInsets.set(mSystemInsets); + mOldStableInsets.set(mStableInsets); + redrawLocked(mNewTargetRect, mFullscreen, mSystemInsets, mStableInsets); } } } /** * The content is about to be drawn and we got the location of where it will be shown. - * If a "changeWindowSizeLocked" call has already been processed, we will re-issue the call + * If a "redrawLocked" call has already been processed, we will re-issue the call * if the previous call was ignored since the size was unknown. * @param xOffset The x offset where the content is drawn to. * @param yOffset The y offset where the content is drawn to. @@ -235,8 +271,8 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame mLastYOffset, mLastXOffset + mLastContentWidth, mLastYOffset + mLastCaptionHeight + mLastContentHeight); - // If this was the first call and changeWindowSizeLocked got already called prior - // to us, we should re-issue a changeWindowSizeLocked now. + // If this was the first call and redrawLocked got already called prior + // to us, we should re-issue a redrawLocked now. return firstCall && (mLastCaptionHeight != 0 || !mDecorView.isShowingCaption()); } @@ -251,16 +287,20 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame } /** - * Resizing the frame to fit the new window size. + * Redraws the background, the caption and the system inset backgrounds if something changed. + * * @param newBounds The window bounds which needs to be drawn. + * @param fullscreen Whether the window is currently drawing in fullscreen. + * @param systemInsets The current visible system insets for the window. + * @param stableInsets The stable insets for the window. */ - private void changeWindowSizeLocked(Rect newBounds) { + private void redrawLocked(Rect newBounds, boolean fullscreen, Rect systemInsets, + Rect stableInsets) { // While a configuration change is taking place the view hierarchy might become // inaccessible. For that case we remember the previous metrics to avoid flashes. // Note that even when there is no visible caption, the caption child will exist. final int captionHeight = mDecorView.getCaptionHeight(); - final int statusBarHeight = mDecorView.getStatusBarHeight(); // The caption height will probably never dynamically change while we are resizing. // Once set to something other then 0 it should be kept that way. @@ -302,14 +342,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame } mFrameAndBackdropNode.end(canvas); - if (mSystemBarBackgroundNode != null && mStatusBarColor != null) { - canvas = mSystemBarBackgroundNode.start(width, height); - mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height); - mStatusBarColor.setBounds(0, 0, left + width, statusBarHeight); - mStatusBarColor.draw(canvas); - mSystemBarBackgroundNode.end(canvas); - mRenderer.drawRenderNode(mSystemBarBackgroundNode); - } + drawColorViews(left, top, width, height, fullscreen, systemInsets, stableInsets); // We need to render the node explicitly mRenderer.drawRenderNode(mFrameAndBackdropNode); @@ -317,6 +350,39 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame reportDrawIfNeeded(); } + private void drawColorViews(int left, int top, int width, int height, + boolean fullscreen, Rect systemInsets, Rect stableInsets) { + if (mSystemBarBackgroundNode == null) { + return; + } + DisplayListCanvas canvas = mSystemBarBackgroundNode.start(width, height); + mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height); + final int topInset = DecorView.getColorViewTopInset(mStableInsets.top, mSystemInsets.top); + final int bottomInset = DecorView.getColorViewBottomInset(stableInsets.bottom, + systemInsets.bottom); + final int rightInset = DecorView.getColorViewRightInset(stableInsets.right, + systemInsets.right); + if (mStatusBarColor != null) { + mStatusBarColor.setBounds(0, 0, left + width, topInset); + mStatusBarColor.draw(canvas); + } + + // We only want to draw the navigation bar if our window is currently fullscreen because we + // don't want the navigation bar background be moving around when resizing in docked mode. + // However, we need it for the transitions into/out of docked mode. + if (mNavigationBarColor != null && fullscreen) { + final int size = DecorView.getNavBarSize(bottomInset, rightInset); + if (DecorView.isNavBarToRightEdge(bottomInset, rightInset)) { + mNavigationBarColor.setBounds(width - size, 0, width, height); + } else { + mNavigationBarColor.setBounds(0, height - size, width, height); + } + mNavigationBarColor.draw(canvas); + } + mSystemBarBackgroundNode.end(canvas); + mRenderer.drawRenderNode(mSystemBarBackgroundNode); + } + /** Notify view root that a frame has been drawn by us, if it has requested so. */ private void reportDrawIfNeeded() { if (mReportNextDraw) { diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 1a20e5ce5793..d4ada957a14a 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -922,6 +922,26 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind return false; } + static int getColorViewTopInset(int stableTop, int systemTop) { + return Math.min(stableTop, systemTop); + } + + static int getColorViewBottomInset(int stableBottom, int systemBottom) { + return Math.min(stableBottom, systemBottom); + } + + static int getColorViewRightInset(int stableRight, int systemRight) { + return Math.min(stableRight, systemRight); + } + + static boolean isNavBarToRightEdge(int bottomInset, int rightInset) { + return bottomInset == 0 && rightInset > 0; + } + + static int getNavBarSize(int bottomInset, int rightInset) { + return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset : bottomInset; + } + WindowInsets updateColorViews(WindowInsets insets, boolean animate) { WindowManager.LayoutParams attrs = mWindow.getAttributes(); int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility(); @@ -933,11 +953,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mLastWindowFlags = attrs.flags; if (insets != null) { - mLastTopInset = Math.min(insets.getStableInsetTop(), + mLastTopInset = getColorViewTopInset(insets.getStableInsetTop(), insets.getSystemWindowInsetTop()); - mLastBottomInset = Math.min(insets.getStableInsetBottom(), + mLastBottomInset = getColorViewBottomInset(insets.getStableInsetBottom(), insets.getSystemWindowInsetBottom()); - mLastRightInset = Math.min(insets.getStableInsetRight(), + mLastRightInset = getColorViewRightInset(insets.getStableInsetRight(), insets.getSystemWindowInsetRight()); // Don't animate if the presence of stable insets has changed, because that @@ -956,8 +976,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mLastHasRightStableInset = hasRightStableInset; } - boolean navBarToRightEdge = mLastBottomInset == 0 && mLastRightInset > 0; - int navBarSize = navBarToRightEdge ? mLastRightInset : mLastBottomInset; + boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset); + int navBarSize = getNavBarSize(mLastBottomInset, mLastRightInset); updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mWindow.mNavigationBarColor, navBarSize, navBarToRightEdge, 0 /* rightInset */, animate && !disallowAnimate, false /* force */); @@ -1041,14 +1061,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind */ private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color, int size, boolean verticalBar, int rightMargin, boolean animate, boolean force) { - state.present = size > 0 && (sysUiVis & state.systemUiHideFlag) == 0 + state.present = (sysUiVis & state.systemUiHideFlag) == 0 && (mWindow.getAttributes().flags & state.hideWindowFlag) == 0 && ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 || force); boolean show = state.present && (color & Color.BLACK) != 0 && ((mWindow.getAttributes().flags & state.translucentFlag) == 0 || force); - boolean showView = show && !isResizing(); + boolean showView = show && !isResizing() && size > 0; boolean visibilityChanged = false; View view = state.view; @@ -1672,7 +1692,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind loadBackgroundDrawablesIfNeeded(); mBackdropFrameRenderer.onResourcesLoaded( this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable, - mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState)); + mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState), + getCurrentColor(mNavigationColorViewState)); } mDecorCaptionView = createDecorCaptionView(inflater); @@ -1854,14 +1875,16 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } @Override - public void onWindowSizeIsChanging(Rect newBounds) { + public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets, + Rect stableInsets) { if (mBackdropFrameRenderer != null) { - mBackdropFrameRenderer.setTargetRect(newBounds); + mBackdropFrameRenderer.setTargetRect(newBounds, fullscreen, systemInsets, stableInsets); } } @Override - public void onWindowDragResizeStart(Rect initialBounds) { + public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets, + Rect stableInsets) { if (mWindow.isDestroyed()) { // If the owner's window is gone, we should not be able to come here anymore. releaseThreadedRenderer(); @@ -1875,7 +1898,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind loadBackgroundDrawablesIfNeeded(); mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer, initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable, - mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState)); + mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState), + getCurrentColor(mNavigationColorViewState), fullscreen, systemInsets, + stableInsets); // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time. // If we want to get the shadow shown while resizing, we would need to elevate a new @@ -1971,10 +1996,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind return isShowingCaption() ? mDecorCaptionView.getCaptionHeight() : 0; } - int getStatusBarHeight() { - return mStatusColorViewState.view != null ? mStatusColorViewState.view.getHeight() : 0; - } - /** * Converts a DIP measure into physical pixels. * @param dip The dip value. diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 02efcc67bee9..ce03bb81c08b 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -322,7 +322,7 @@ public final class FloatingToolbar { /* View components */ private final ViewGroup mContentContainer; // holds all contents. private final ViewGroup mMainPanel; // holds menu items that are initially displayed. - private final ListView mOverflowPanel; // holds menu items hidden in the overflow. + private final OverflowPanel mOverflowPanel; // holds menu items hidden in the overflow. private final ImageButton mOverflowButton; // opens/closes the overflow. /* overflow button drawables. */ private final Drawable mArrow; @@ -895,6 +895,7 @@ public final class FloatingToolbar { private void setPanelsStatesAtRestingPosition() { mOverflowButton.setEnabled(true); + mOverflowPanel.awakenScrollBars(); if (mIsOverflowOpen) { // Set open state. @@ -1333,27 +1334,8 @@ public final class FloatingToolbar { return overflowButton; } - private ListView createOverflowPanel() { - final ListView overflowPanel = new ListView(FloatingToolbarPopup.this.mContext) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // Update heightMeasureSpec to make sure that this view is not clipped - // as we offset it's coordinates with respect to it's parent. - heightMeasureSpec = MeasureSpec.makeMeasureSpec( - mOverflowPanelSize.getHeight() - mOverflowButtonSize.getHeight(), - MeasureSpec.EXACTLY); - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - if (isOverflowAnimating()) { - // Eat the touch event. - return true; - } - return super.dispatchTouchEvent(ev); - } - }; + private OverflowPanel createOverflowPanel() { + final OverflowPanel overflowPanel = new OverflowPanel(this); overflowPanel.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); overflowPanel.setDivider(null); @@ -1464,6 +1446,43 @@ public final class FloatingToolbar { } /** + * A custom ListView for the overflow panel. + */ + private static final class OverflowPanel extends ListView { + + private final FloatingToolbarPopup mPopup; + + OverflowPanel(FloatingToolbarPopup popup) { + super(Preconditions.checkNotNull(popup).mContext); + this.mPopup = popup; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Update heightMeasureSpec to make sure that this view is not clipped + // as we offset it's coordinates with respect to it's parent. + int height = mPopup.mOverflowPanelSize.getHeight() + - mPopup.mOverflowButtonSize.getHeight(); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (mPopup.isOverflowAnimating()) { + // Eat the touch event. + return true; + } + return super.dispatchTouchEvent(ev); + } + + @Override + protected boolean awakenScrollBars() { + return super.awakenScrollBars(); + } + } + + /** * A custom interpolator used for various floating toolbar animations. */ private static final class LogAccelerateInterpolator implements Interpolator { diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 1b6b53ae49f4..ffa3fa631b82 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -51,7 +51,6 @@ LOCAL_SRC_FILES:= \ android_database_SQLiteConnection.cpp \ android_database_SQLiteGlobal.cpp \ android_database_SQLiteDebug.cpp \ - android_graphics_drawable_AnimatedVectorDrawable.cpp \ android_graphics_drawable_VectorDrawable.cpp \ android_view_DisplayEventReceiver.cpp \ android_view_DisplayListCanvas.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 223fc1af46d5..2e45f8c4d9c0 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -131,7 +131,6 @@ extern int register_android_graphics_Rasterizer(JNIEnv* env); extern int register_android_graphics_Region(JNIEnv* env); extern int register_android_graphics_SurfaceTexture(JNIEnv* env); extern int register_android_graphics_Xfermode(JNIEnv* env); -extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env); extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env); extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env); extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env); @@ -1322,7 +1321,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_Typeface), REG_JNI(register_android_graphics_Xfermode), REG_JNI(register_android_graphics_YuvImage), - REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable), REG_JNI(register_android_graphics_drawable_VectorDrawable), REG_JNI(register_android_graphics_pdf_PdfDocument), REG_JNI(register_android_graphics_pdf_PdfEditor), diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 3d5091a78687..bd01c73adf80 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -746,10 +746,12 @@ void RecyclingClippingPixelAllocator::copyIfNecessary() { if (mNeedsCopy) { SkPixelRef* recycledPixels = mRecycledBitmap->refPixelRef(); void* dst = recycledPixels->pixels(); - size_t dstRowBytes = mRecycledBitmap->rowBytes(); - size_t bytesToCopy = SkTMin(mRecycledBitmap->info().minRowBytes(), + const size_t dstRowBytes = mRecycledBitmap->rowBytes(); + const size_t bytesToCopy = std::min(mRecycledBitmap->info().minRowBytes(), mSkiaBitmap->info().minRowBytes()); - for (int y = 0; y < mRecycledBitmap->info().height(); y++) { + const int rowsToCopy = std::min(mRecycledBitmap->info().height(), + mSkiaBitmap->info().height()); + for (int y = 0; y < rowsToCopy; y++) { memcpy(dst, mSkiaBitmap->getAddr(0, y), bytesToCopy); dst = SkTAddOffset<void>(dst, dstRowBytes); } diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index 35b5016e1b07..cf73316d494b 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -510,7 +510,7 @@ public: size_t glyphCount = end - start; - if (CC_UNLIKELY(canvas->isHighContrastText())) { + if (CC_UNLIKELY(canvas->isHighContrastText() && paint.getAlpha() != 0)) { // high contrast draw path int color = paint.getColor(); int channelSum = SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color); diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp deleted file mode 100644 index 7a3c598e0aed..000000000000 --- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#define LOG_TAG "OpenGLRenderer" - -#include "jni.h" -#include "GraphicsJNI.h" -#include "core_jni_helpers.h" -#include "log/log.h" - -#include "Animator.h" -#include "Interpolator.h" -#include "PropertyValuesAnimatorSet.h" -#include "PropertyValuesHolder.h" -#include "VectorDrawable.h" - -namespace android { -using namespace uirenderer; -using namespace VectorDrawable; - -static struct { - jclass clazz; - jmethodID callOnFinished; -} gVectorDrawableAnimatorClassInfo; - -static JNIEnv* getEnv(JavaVM* vm) { - JNIEnv* env; - if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { - return 0; - } - return env; -} - -static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener) { - class AnimationListenerBridge : public AnimationListener { - public: - AnimationListenerBridge(JNIEnv* env, jobject finishListener) { - mFinishListener = env->NewGlobalRef(finishListener); - env->GetJavaVM(&mJvm); - } - - virtual ~AnimationListenerBridge() { - if (mFinishListener) { - onAnimationFinished(NULL); - } - } - - virtual void onAnimationFinished(BaseRenderNodeAnimator*) { - LOG_ALWAYS_FATAL_IF(!mFinishListener, "Finished listener twice?"); - JNIEnv* env = getEnv(mJvm); - env->CallStaticVoidMethod( - gVectorDrawableAnimatorClassInfo.clazz, - gVectorDrawableAnimatorClassInfo.callOnFinished, - mFinishListener); - releaseJavaObject(); - } - - private: - void releaseJavaObject() { - JNIEnv* env = getEnv(mJvm); - env->DeleteGlobalRef(mFinishListener); - mFinishListener = NULL; - } - - JavaVM* mJvm; - jobject mFinishListener; - }; - return new AnimationListenerBridge(env, finishListener); -} - -static void addAnimator(JNIEnv*, jobject, jlong animatorSetPtr, jlong propertyHolderPtr, - jlong interpolatorPtr, jlong startDelay, jlong duration, jint repeatCount) { - PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr); - PropertyValuesHolder* holder = reinterpret_cast<PropertyValuesHolder*>(propertyHolderPtr); - Interpolator* interpolator = reinterpret_cast<Interpolator*>(interpolatorPtr); - set->addPropertyAnimator(holder, interpolator, startDelay, duration, repeatCount); -} - -static jlong createAnimatorSet(JNIEnv*, jobject) { - PropertyValuesAnimatorSet* animatorSet = new PropertyValuesAnimatorSet(); - return reinterpret_cast<jlong>(animatorSet); -} - -static jlong createGroupPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId, - jfloat startValue, jfloat endValue) { - VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(nativePtr); - GroupPropertyValuesHolder* newHolder = new GroupPropertyValuesHolder(group, propertyId, - startValue, endValue); - return reinterpret_cast<jlong>(newHolder); -} - -static jlong createPathDataPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jlong startValuePtr, - jlong endValuePtr) { - VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(nativePtr); - PathData* startData = reinterpret_cast<PathData*>(startValuePtr); - PathData* endData = reinterpret_cast<PathData*>(endValuePtr); - PathDataPropertyValuesHolder* newHolder = new PathDataPropertyValuesHolder(path, - startData, endData); - return reinterpret_cast<jlong>(newHolder); -} - -static jlong createPathColorPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId, - int startValue, jint endValue) { - VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(nativePtr); - FullPathColorPropertyValuesHolder* newHolder = new FullPathColorPropertyValuesHolder(fullPath, - propertyId, startValue, endValue); - return reinterpret_cast<jlong>(newHolder); -} - -static jlong createPathPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId, - float startValue, jfloat endValue) { - VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(nativePtr); - FullPathPropertyValuesHolder* newHolder = new FullPathPropertyValuesHolder(fullPath, - propertyId, startValue, endValue); - return reinterpret_cast<jlong>(newHolder); -} - -static jlong createRootAlphaPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jfloat startValue, - float endValue) { - VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(nativePtr); - RootAlphaPropertyValuesHolder* newHolder = new RootAlphaPropertyValuesHolder(tree, - startValue, endValue); - return reinterpret_cast<jlong>(newHolder); -} -static void setPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr, - jfloatArray srcData, jint length) { - - jfloat* propertyData = env->GetFloatArrayElements(srcData, nullptr); - PropertyValuesHolder* holder = reinterpret_cast<PropertyValuesHolder*>(propertyHolderPtr); - holder->setPropertyDataSource(propertyData, length); - env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT); -} -static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) { - PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr); - // TODO: keep a ref count in finish listener - AnimationListener* listener = createAnimationListener(env, finishListener); - set->start(listener); -} - -static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) { - // TODO: implement reverse -} - -static void end(JNIEnv*, jobject, jlong animatorSetPtr) { - PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr); - set->end(); -} - -static void reset(JNIEnv*, jobject, jlong animatorSetPtr) { - PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr); - set->reset(); -} - -static const JNINativeMethod gMethods[] = { - {"nCreateAnimatorSet", "()J", (void*)createAnimatorSet}, - {"nAddAnimator", "(JJJJJI)V", (void*)addAnimator}, - {"nCreateGroupPropertyHolder", "!(JIFF)J", (void*)createGroupPropertyHolder}, - {"nCreatePathDataPropertyHolder", "!(JJJ)J", (void*)createPathDataPropertyHolder}, - {"nCreatePathColorPropertyHolder", "!(JIII)J", (void*)createPathColorPropertyHolder}, - {"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder}, - {"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder}, - {"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData}, - {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)start}, - {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)reverse}, - {"nEnd", "!(J)V", (void*)end}, - {"nReset", "!(J)V", (void*)reset}, -}; - -const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator"; -int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) { - gVectorDrawableAnimatorClassInfo.clazz = FindClassOrDie(env, kClassPathName); - gVectorDrawableAnimatorClassInfo.clazz = MakeGlobalRefOrDie(env, - gVectorDrawableAnimatorClassInfo.clazz); - - gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie( - env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished", - "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V"); - return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable", - gMethods, NELEM(gMethods)); -} - -}; // namespace android diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp index e88287644555..563ec8bd9834 100644 --- a/core/jni/android_graphics_drawable_VectorDrawable.cpp +++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp @@ -32,6 +32,11 @@ static jlong createTree(JNIEnv*, jobject, jlong groupPtr) { return reinterpret_cast<jlong>(tree); } +static void deleteTree(JNIEnv*, jobject, jlong treePtr) { + VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr); + delete tree; +} + static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr, jfloat viewportWidth, jfloat viewportHeight) { VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr); @@ -328,6 +333,7 @@ static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPa static const JNINativeMethod gMethods[] = { {"nCreateRenderer", "!(J)J", (void*)createTree}, + {"nDestroyRenderer", "!(J)V", (void*)deleteTree}, {"nSetRendererViewportSize", "!(JFF)V", (void*)setTreeViewportSize}, {"nSetRootAlpha", "!(JF)Z", (void*)setRootAlpha}, {"nGetRootAlpha", "!(J)F", (void*)getRootAlpha}, diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp index a6c61dedb103..03c94a683ec2 100644 --- a/core/jni/android_view_DisplayListCanvas.cpp +++ b/core/jni/android_view_DisplayListCanvas.cpp @@ -27,13 +27,8 @@ #include <SkBitmap.h> #include <SkRegion.h> -#if HWUI_NEW_OPS -#include <RecordingCanvas.h> -typedef android::uirenderer::RecordingCanvas canvas_t; -#else -#include <DisplayListCanvas.h> -typedef android::uirenderer::DisplayListCanvas canvas_t; -#endif + +#include <Canvas.h> #include <Rect.h> #include <RenderNode.h> #include <CanvasProperty.h> @@ -52,7 +47,7 @@ using namespace uirenderer; static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz, jlong canvasPtr, jboolean reorderEnable) { - canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr); + Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); canvas->insertReorderBarrier(reorderEnable); } @@ -62,7 +57,7 @@ static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, job static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz, jlong canvasPtr, jlong functorPtr) { - canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr); + Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); Functor* functor = reinterpret_cast<Functor*>(functorPtr); canvas->callDrawGLFunction(functor); } @@ -92,7 +87,7 @@ static jint android_view_DisplayListCanvas_getMaxTextureHeight(JNIEnv* env, jobj static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz, jlong canvasPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr, jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) { - canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr); + Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr); CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr); CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr); @@ -105,7 +100,7 @@ static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobje static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz, jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) { - canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr); + Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr); CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr); CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr); @@ -119,25 +114,25 @@ static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env, jobject clazz, jlong canvasPtr) { - canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr); + Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); return reinterpret_cast<jlong>(canvas->finishRecording()); } static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz, jint width, jint height) { - return reinterpret_cast<jlong>(new canvas_t(width, height)); + return reinterpret_cast<jlong>(Canvas::create_recording_canvas(width, height)); } static void android_view_DisplayListCanvas_resetDisplayListCanvas(JNIEnv* env, jobject clazz, jlong canvasPtr, jint width, jint height) { - canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr); - canvas->reset(width, height); + Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); + canvas->resetRecording(width, height); } static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env, jobject clazz, jlong canvasPtr, jlong renderNodePtr) { - canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr); + Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); canvas->drawRenderNode(renderNode); } @@ -148,7 +143,7 @@ static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env, static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz, jlong canvasPtr, jlong layerPtr) { - canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr); + Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr); canvas->drawLayer(layer); } diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index b1d4e2646ba4..a9003c1888d2 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -15,6 +15,7 @@ */ #define LOG_TAG "OpenGLRenderer" +#define ATRACE_TAG ATRACE_TAG_VIEW #include <EGL/egl.h> @@ -24,7 +25,10 @@ #include <android_runtime/AndroidRuntime.h> #include <Animator.h> +#include <DamageAccumulator.h> +#include <Matrix.h> #include <RenderNode.h> +#include <TreeInfo.h> #include <Paint.h> #include "core_jni_helpers.h" @@ -462,6 +466,69 @@ static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz, } // ---------------------------------------------------------------------------- +// SurfaceView position callback +// ---------------------------------------------------------------------------- + +jmethodID gSurfaceViewPositionUpdateMethod; + +static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, + jlong renderNodePtr, jobject surfaceview) { + class SurfaceViewPositionUpdater : public RenderNode::PositionListener { + public: + SurfaceViewPositionUpdater(JNIEnv* env, jobject surfaceview) { + env->GetJavaVM(&mVm); + mWeakRef = env->NewWeakGlobalRef(surfaceview); + } + + virtual ~SurfaceViewPositionUpdater() { + jnienv()->DeleteWeakGlobalRef(mWeakRef); + mWeakRef = nullptr; + } + + virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override { + if (CC_UNLIKELY(!mWeakRef || !info.updateWindowPositions)) return; + ATRACE_NAME("Update SurfaceView position"); + + JNIEnv* env = jnienv(); + jobject localref = env->NewLocalRef(mWeakRef); + if (CC_UNLIKELY(!localref)) { + jnienv()->DeleteWeakGlobalRef(mWeakRef); + mWeakRef = nullptr; + return; + } + Matrix4 transform; + info.damageAccumulator->computeCurrentTransform(&transform); + const RenderProperties& props = node.properties(); + uirenderer::Rect bounds(props.getWidth(), props.getHeight()); + transform.mapRect(bounds); + bounds.left -= info.windowInsetLeft; + bounds.right -= info.windowInsetLeft; + bounds.top -= info.windowInsetTop; + bounds.bottom -= info.windowInsetTop; + env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod, + (jlong) info.frameNumber, (jint) bounds.left, (jint) bounds.top, + (jint) bounds.right, (jint) bounds.bottom); + env->DeleteLocalRef(localref); + } + + private: + JNIEnv* jnienv() { + JNIEnv* env; + if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", mVm); + } + return env; + } + + JavaVM* mVm; + jobject mWeakRef; + }; + + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->setPositionListener(new SurfaceViewPositionUpdater(env, surfaceview)); +} + +// ---------------------------------------------------------------------------- // JNI Glue // ---------------------------------------------------------------------------- @@ -539,9 +606,14 @@ static const JNINativeMethod gMethods[] = { { "nAddAnimator", "(JJ)V", (void*) android_view_RenderNode_addAnimator }, { "nEndAllAnimators", "(J)V", (void*) android_view_RenderNode_endAllAnimators }, + + { "nRequestPositionUpdates", "(JLandroid/view/SurfaceView;)V", (void*) android_view_RenderNode_requestPositionUpdates }, }; int register_android_view_RenderNode(JNIEnv* env) { + jclass clazz = FindClassOrDie(env, "android/view/SurfaceView"); + gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz, + "updateWindowPositionRT", "(JIIII)V"); return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 8c907dd35a1e..acd0501362b5 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -134,7 +134,14 @@ public: virtual void prepareTree(TreeInfo& info) { info.errorHandler = this; + // TODO: This is hacky + info.windowInsetLeft = -stagingProperties().getLeft(); + info.windowInsetTop = -stagingProperties().getTop(); + info.updateWindowPositions = true; RenderNode::prepareTree(info); + info.updateWindowPositions = false; + info.windowInsetLeft = 0; + info.windowInsetTop = 0; info.errorHandler = NULL; } @@ -369,28 +376,28 @@ static void android_view_ThreadedRenderer_setName(JNIEnv* env, jobject clazz, static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz, jlong proxyPtr, jobject jsurface) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface); - proxy->initialize(window); + sp<Surface> surface = android_view_Surface_getSurface(env, jsurface); + proxy->initialize(surface); } static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz, jlong proxyPtr, jobject jsurface) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - sp<ANativeWindow> window; + sp<Surface> surface; if (jsurface) { - window = android_view_Surface_getNativeWindow(env, jsurface); + surface = android_view_Surface_getSurface(env, jsurface); } - proxy->updateSurface(window); + proxy->updateSurface(surface); } static jboolean android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz, jlong proxyPtr, jobject jsurface) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - sp<ANativeWindow> window; + sp<Surface> surface; if (jsurface) { - window = android_view_Surface_getNativeWindow(env, jsurface); + surface = android_view_Surface_getSurface(env, jsurface); } - return proxy->pauseSurface(window); + return proxy->pauseSurface(surface); } static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7729d48c2452..cc489022345c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -292,9 +292,12 @@ <protected-broadcast android:name="android.intent.action.REMOTE_BUGREPORT_FINISHED" /> <protected-broadcast android:name="android.intent.action.REMOTE_BUGREPORT_DISPATCH" /> + <!-- Legacy --> <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" /> <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" /> + <protected-broadcast android:name="com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE" /> + <protected-broadcast android:name="android.intent.action.HDMI_PLUGGED" /> <protected-broadcast android:name="android.intent.action.PHONE_STATE" /> @@ -2874,6 +2877,12 @@ <permission android:name="android.permission.MANAGE_SOUND_TRIGGER" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows trusted applications to dispatch managed provisioning message to Managed + Provisioning app. If requesting app does not have permission, it will be ignored. + @hide --> + <permission android:name="android.permission.DISPATCH_PROVISIONING_MESSAGE" + android:protectionLevel="signature|privileged" /> + <application android:process="system" android:persistent="true" android:hasCode="false" diff --git a/core/res/res/drawable/ic_close.xml b/core/res/res/drawable/ic_close.xml new file mode 100644 index 000000000000..708695994ab6 --- /dev/null +++ b/core/res/res/drawable/ic_close.xml @@ -0,0 +1,24 @@ +<!-- +Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z" + android:fillColor="#FF000000"/> +</vector> diff --git a/core/res/res/drawable/ic_feedback.xml b/core/res/res/drawable/ic_feedback.xml new file mode 100644 index 000000000000..b2d1cb80c9c1 --- /dev/null +++ b/core/res/res/drawable/ic_feedback.xml @@ -0,0 +1,27 @@ +<!-- +Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:pathData="M0 0h24v24H0z" + android:fillColor="#00000000"/> + <path + android:fillColor="#FF000000" + android:pathData="M20.0,2.0L4.0,2.0c-1.1,0.0 -1.9,0.9 -1.99,2.0L2.0,22.0l4.0,-4.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L22.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,12.0l-2.0,0.0l0.0,-2.0l2.0,0.0l0.0,2.0zm0.0,-4.0l-2.0,0.0L11.0,6.0l2.0,0.0l0.0,4.0z"/> +</vector> diff --git a/core/res/res/drawable/ic_refresh.xml b/core/res/res/drawable/ic_refresh.xml new file mode 100644 index 000000000000..1f671684861f --- /dev/null +++ b/core/res/res/drawable/ic_refresh.xml @@ -0,0 +1,27 @@ +<!-- +Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/> + <path + android:pathData="M0 0h24v24H0z" + android:fillColor="#00000000"/> +</vector> diff --git a/core/res/res/drawable/ic_schedule.xml b/core/res/res/drawable/ic_schedule.xml new file mode 100644 index 000000000000..899dc821844e --- /dev/null +++ b/core/res/res/drawable/ic_schedule.xml @@ -0,0 +1,30 @@ +<!-- +Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF000000" + android:pathData="M11.99,2.0C6.47,2.0 2.0,6.48 2.0,12.0s4.47,10.0 9.99,10.0C17.52,22.0 22.0,17.52 22.0,12.0S17.52,2.0 11.99,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.58 -8.0,-8.0s3.58,-8.0 8.0,-8.0 8.0,3.58 8.0,8.0 -3.58,8.0 -8.0,8.0z"/> + <path + android:pathData="M0 0h24v24H0z" + android:fillColor="#00000000"/> + <path + android:fillColor="#FF000000" + android:pathData="M12.5,7.0L11.0,7.0l0.0,6.0l5.25,3.1 0.75,-1.23 -4.5,-2.67z"/> +</vector> diff --git a/core/res/res/layout/app_anr_dialog.xml b/core/res/res/layout/app_anr_dialog.xml index e8169ee1bc86..8bef116fa89e 100644 --- a/core/res/res/layout/app_anr_dialog.xml +++ b/core/res/res/layout/app_anr_dialog.xml @@ -18,28 +18,31 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingTop="@dimen/dialog_list_padding_vertical_material" + android:paddingTop="@dimen/aerr_padding_list_top" android:paddingBottom="@dimen/dialog_list_padding_vertical_material"> - <TextView + <Button android:id="@+id/aerr_close" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/aerr_close_app" + android:drawableStart="@drawable/ic_close" style="@style/aerr_list_item" /> - <TextView + <Button android:id="@+id/aerr_wait" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/aerr_wait" + android:drawableStart="@drawable/ic_schedule" style="@style/aerr_list_item" /> - <TextView + <Button android:id="@+id/aerr_report" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/aerr_report" + android:drawableStart="@drawable/ic_feedback" style="@style/aerr_list_item" /> </LinearLayout> diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml index 46a2b2af1a28..824f97f6585a 100644 --- a/core/res/res/layout/app_error_dialog.xml +++ b/core/res/res/layout/app_error_dialog.xml @@ -21,9 +21,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingTop="@dimen/dialog_list_padding_vertical_material" - android:paddingBottom="@dimen/dialog_list_padding_vertical_material" -> + android:paddingTop="@dimen/aerr_padding_list_top" + android:paddingBottom="@dimen/dialog_list_padding_vertical_material"> <Button @@ -31,6 +30,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/aerr_restart" + android:drawableStart="@drawable/ic_refresh" style="@style/aerr_list_item" /> @@ -39,6 +39,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/aerr_reset" + android:drawableStart="@drawable/ic_refresh" style="@style/aerr_list_item" /> @@ -47,6 +48,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/aerr_report" + android:drawableStart="@drawable/ic_feedback" style="@style/aerr_list_item" /> @@ -55,6 +57,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/aerr_close" + android:drawableStart="@drawable/ic_close" style="@style/aerr_list_item" /> @@ -63,6 +66,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/aerr_mute" + android:drawableStart="@drawable/ic_close" style="@style/aerr_list_item" /> diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml index b45f8bb92e18..6669baedcfab 100644 --- a/core/res/res/layout/notification_template_header.xml +++ b/core/res/res/layout/notification_template_header.xml @@ -87,7 +87,6 @@ android:layout_marginStart="2dp" android:layout_marginEnd="2dp" android:visibility="gone" - android:maxWidth="72dp" android:singleLine="true"/> <TextView android:id="@+id/time_divider" diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml index 0a7ac776744a..305c8b0a0c0f 100644 --- a/core/res/res/layout/resolve_grid_item.xml +++ b/core/res/res/layout/resolve_grid_item.xml @@ -25,6 +25,7 @@ android:gravity="center" android:paddingTop="8dp" android:paddingBottom="8dp" + android:focusable="true" android:background="?attr/selectableItemBackgroundBorderless"> <FrameLayout android:layout_width="wrap_content" diff --git a/core/res/res/menu/language_selection_list.xml b/core/res/res/menu/language_selection_list.xml index 63b962740e75..377c4fab962a 100644 --- a/core/res/res/menu/language_selection_list.xml +++ b/core/res/res/menu/language_selection_list.xml @@ -14,12 +14,12 @@ limitations under the License. --> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/locale_search_menu" android:title="@string/locale_search_menu" - app:showAsAction="always" - app:actionViewClass="android.widget.SearchView" /> + android:icon="@*android:drawable/ic_search_api_material" + android:showAsAction="always|collapseActionView" + android:actionViewClass="android.widget.SearchView" /> </menu> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index b4c557603ea9..c8ab29558a26 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -232,7 +232,7 @@ <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud versteek"</string> - <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhoud word versteek deur beleid"</string> + <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhoud word versteek volgens beleid"</string> <string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string> <string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string> <string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string> @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-kaart bygevoeg"</string> <string name="sim_added_message" msgid="7797975656153714319">"Herbegin jou toestel om toegang tot die sellulêre netwerk te verkry."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Herbegin"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Jy sal \'n program van jou diensverskaffer af moet installeer en oopmaak om jou nuwe SIM behoorlik te laat werk."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"KRY DIE PROGRAM"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NIE NOU NIE"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Nuwe SIM is ingesit"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Tik om dit op te stel"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Stel tyd"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Stel datum"</string> <string name="date_time_set" msgid="5777075614321087758">"Stel"</string> @@ -1550,11 +1555,12 @@ <string name="suspended_package_message" msgid="6341091587106868601">"Deur %1$s-administrateur gedeaktiveer. Kontak hulle om meer uit te vind."</string> <string name="new_sms_notification_title" msgid="8442817549127555977">"Jy het nuwe boodskappe"</string> <string name="new_sms_notification_content" msgid="7002938807812083463">"Maak SMS-program oop om te bekyk"</string> - <string name="user_encrypted_title" msgid="7664361246988454307">"Sommige funksies sal dalk nie beskikbaar wees nie"</string> + <string name="user_encrypted_title" msgid="7664361246988454307">"Party funksies dalk nie beskikbaar nie"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Raak om voort te gaan"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Gebruikerprofiel is gesluit"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Gekoppel aan <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tik om lêers te bekyk"</string> + <string name="pin_target" msgid="3052256031352291362">"Speld vas"</string> + <string name="unpin_target" msgid="3556545602439143442">"Ontspeld"</string> + <string name="app_info" msgid="6856026610594615344">"Programinligting"</string> </resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 94419c02da8a..461c78a0afda 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1031,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM ካርድ አክል"</string> <string name="sim_added_message" msgid="7797975656153714319">"የተንቀሳቃሽ ስልክ አውታረ መረብ ለመድረስ መሣሪያዎን ዳግም ያስጀምሩት።"</string> <string name="sim_restart_button" msgid="4722407842815232347">"ዳግም ጀምር"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"ጊዜ አዘጋጅ"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"ውሂብ አዘጋጅ"</string> <string name="date_time_set" msgid="5777075614321087758">"አዘጋጅ"</string> @@ -1553,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"አንዳንድ ተግባሮች ላይገኙ ይችላሉ"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"ለመቀጠል ይንኩ"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"የተጠቃሚ መገለጫ ተቆልፏል"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"ከ<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ጋር ተገናኝቷል"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ፋይሎችን ለመመልከት መታ ያድርጉ"</string> + <string name="pin_target" msgid="3052256031352291362">"ፒን"</string> + <string name="unpin_target" msgid="3556545602439143442">"ንቀል"</string> + <string name="app_info" msgid="6856026610594615344">"የመተግበሪያ መረጃ"</string> </resources> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 8a6df9d2450a..e927d5418099 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1063,6 +1063,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"تمت إضافة شريحة SIM"</string> <string name="sim_added_message" msgid="7797975656153714319">"أعد تشغيل جهازك للدخول إلى شبكة الجوّال."</string> <string name="sim_restart_button" msgid="4722407842815232347">"إعادة التشغيل"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"لتشغيل شريحة SIM الجديدة بشكل سليم، يجب تثبيت تطبيق من مشغّل شبكة الجوّال وفتحه."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"الحصول على التطبيق"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"ليس الآن"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"تم إدخال شريحة SIM جديدة."</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"انقر لإعداده."</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"تعيين الوقت"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"تعيين التاريخ"</string> <string name="date_time_set" msgid="5777075614321087758">"تعيين"</string> @@ -1629,8 +1634,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"قد لا تكون بعض الوظائف متاحة"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"المس للمتابعة"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"تم قفل الملف الشخصي للمستخدم"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"تم الاتصال بـ <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"انقر لعرض الملفات"</string> + <string name="pin_target" msgid="3052256031352291362">"تثبيت"</string> + <string name="unpin_target" msgid="3556545602439143442">"إزالة تثبيت"</string> + <string name="app_info" msgid="6856026610594615344">"معلومات عن التطبيق"</string> </resources> diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml index c3cbe4a43b6b..211346fa6803 100644 --- a/core/res/res/values-az-rAZ/strings.xml +++ b/core/res/res/values-az-rAZ/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SİM kart əlavə edildi"</string> <string name="sim_added_message" msgid="7797975656153714319">"Mobil şəbəkəyə giriş üçün cihazınızı sıfırlayın."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Yenidən başlat"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Yeni SIM kartınızın düzgün işləməsi üçün, operatorunuzdan tətbiq yükləməli və açmalısınız."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"TƏTBİQİ ƏLDƏ EDİN"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"İNDİ YOX"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Yeni SIM kart taxılıb"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Quraşdırmaq üçün tıklayın"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Vaxt ayarlayın"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Tarixi quraşdır"</string> <string name="date_time_set" msgid="5777075614321087758">"Ayarlayın"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Bəzi funksiyalar əlçatan olmaya bilər"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Davam etmək üçün toxunun"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"İstifadəçi profili kilidlidir"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> məhsuluna bağlandı"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Faylları görmək üçün basın"</string> + <string name="pin_target" msgid="3052256031352291362">"Pin kod"</string> + <string name="unpin_target" msgid="3556545602439143442">"Çıxarın"</string> + <string name="app_info" msgid="6856026610594615344">"Tətbiq məlumatı"</string> </resources> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 293fcbd09e80..7e27050d7fbe 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1039,6 +1039,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM kartica je dodata"</string> <string name="sim_added_message" msgid="7797975656153714319">"Ponovo pokrenite uređaj da biste pristupili mobilnoj mreži."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Ponovo pokreni"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Podešavanje vremena"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Podešavanje datuma"</string> <string name="date_time_set" msgid="5777075614321087758">"Podesi"</string> @@ -1572,8 +1582,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Neke funkcije nisu dostupne"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Dodirnite da biste nastavili"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profil korisnika je zaključan"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Povezano je sa proizvodom <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dodirnite za pregled datoteka"</string> + <string name="pin_target" msgid="3052256031352291362">"Zakači"</string> + <string name="unpin_target" msgid="3556545602439143442">"Otkači"</string> + <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 4426d07f08ec..84834ee5c44d 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1031,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM картата е добавена"</string> <string name="sim_added_message" msgid="7797975656153714319">"Рестартирайте устройството си, за да осъществите достъп до клетъчната мрежа."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Рестартиране"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Задаване на часа"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Задаване на дата"</string> <string name="date_time_set" msgid="5777075614321087758">"Задаване"</string> @@ -1553,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Някои функции може да не са налице"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Докоснете, за да продължите"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Потр. профил е заключен"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Установена е връзка с <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Докоснете, за да прегледате файловете"</string> + <string name="pin_target" msgid="3052256031352291362">"Фиксиране"</string> + <string name="unpin_target" msgid="3556545602439143442">"Освобождаване"</string> + <string name="app_info" msgid="6856026610594615344">"Информация за приложението"</string> </resources> diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml index 2abddb4dfffe..db2df411886f 100644 --- a/core/res/res/values-bn-rBD/strings.xml +++ b/core/res/res/values-bn-rBD/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"সিম কার্ড যোগ করা হয়েছে"</string> <string name="sim_added_message" msgid="7797975656153714319">"সেলুলার নেটওয়ার্ক অ্যাক্সেস করতে আপনার ডিভাইস পুনর্সূচনা করুন"</string> <string name="sim_restart_button" msgid="4722407842815232347">"পুনর্সূচনা"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"যাতে আপনার নতুন SIM সঠিকভাবে কাজ করে, তার জন্য আপনাকে আপনার পরিষেবা প্রদানকারীর থেকে একটি অ্যাপ্লিকেশান ইনস্টল করতে এবং খুলতে হবে৷"</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"অ্যাপ্লিকেশানটি পান"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"এখনই নয়"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"নতুন SIM ঢোকানো হয়েছে"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"এটিকে সেট আপ করতে আলতো চাপুন"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"সময় সেট করুন"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"তারিখ সেট করুন"</string> <string name="date_time_set" msgid="5777075614321087758">"সেট করুন"</string> @@ -1551,10 +1556,11 @@ <string name="new_sms_notification_title" msgid="8442817549127555977">"আপনার নতুন বার্তা আছে"</string> <string name="new_sms_notification_content" msgid="7002938807812083463">"দেখার জন্য SMS অ্যাপ্লিকেশান খুলুন"</string> <string name="user_encrypted_title" msgid="7664361246988454307">"কিছু ক্রিয়াকলাপ উপলব্ধ নাও হতে পারে"</string> - <string name="user_encrypted_message" msgid="7504541494700807850">"অবিরততে স্পর্শ করুন"</string> + <string name="user_encrypted_message" msgid="7504541494700807850">"অবিরত রাখতে স্পর্শ করুন"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"ব্যবহারকারীর প্রোফাইল লক করা আছে"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> এর সাথে সংযুক্ত হয়েছে"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ফাইলগুলি দেখতে আলতো চাপ দিন"</string> + <string name="pin_target" msgid="3052256031352291362">"পিন করুন"</string> + <string name="unpin_target" msgid="3556545602439143442">"আনপিন করুন"</string> + <string name="app_info" msgid="6856026610594615344">"অ্যাপ্লিকেশানের তথ্য"</string> </resources> diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml index d68f9baba36c..7a1c98809828 100644 --- a/core/res/res/values-bs-rBA/strings.xml +++ b/core/res/res/values-bs-rBA/strings.xml @@ -1905,6 +1905,16 @@ <skip /> <!-- no translation found for sim_restart_button (4722407842815232347) --> <skip /> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <!-- no translation found for time_picker_dialog_title (8349362623068819295) --> <skip /> <!-- no translation found for date_picker_dialog_title (5879450659453782278) --> @@ -2859,8 +2869,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Neke funkcije možda neće biti dostupne"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Dodirnite da biste nastavili"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profil korisnika je zaključan"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Povezan na <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dodirnite za prikaz datoteka"</string> + <string name="pin_target" msgid="3052256031352291362">"Zakači"</string> + <string name="unpin_target" msgid="3556545602439143442">"Otkači"</string> + <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 19e4ae4a0ae2..0f971b24a9dd 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1031,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"Addició de la targeta SIM"</string> <string name="sim_added_message" msgid="7797975656153714319">"Reinicia el dispositiu per accedir a la xarxa mòbil."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Reinicia"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Defineix l\'hora"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Establiment de data"</string> <string name="date_time_set" msgid="5777075614321087758">"Defineix"</string> @@ -1550,11 +1560,12 @@ <string name="suspended_package_message" msgid="6341091587106868601">"L\'administrador de l\'empresa %1$s ha desactivat el paquet. Contacta-hi per obtenir-ne més informació."</string> <string name="new_sms_notification_title" msgid="8442817549127555977">"Tens missatges nous"</string> <string name="new_sms_notification_content" msgid="7002938807812083463">"Obre l\'aplicació de SMS per veure\'ls"</string> - <string name="user_encrypted_title" msgid="7664361246988454307">"Hi pot haver func. no dispon."</string> + <string name="user_encrypted_title" msgid="7664361246988454307">"Hi pot haver funcions no disponibles"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Toca per continuar"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil d\'usuari bloquejat"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"S\'ha connectat a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toca per veure els fitxers"</string> + <string name="pin_target" msgid="3052256031352291362">"Fixa"</string> + <string name="unpin_target" msgid="3556545602439143442">"No fixis"</string> + <string name="app_info" msgid="6856026610594615344">"Informació de l\'aplicació"</string> </resources> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index e05ab549d042..d0716469564a 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1047,6 +1047,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM karta přidána."</string> <string name="sim_added_message" msgid="7797975656153714319">"Mobilní síť bude přístupná po restartu zařízení."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Restartovat"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Nastavit čas"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Nastavení data"</string> <string name="date_time_set" msgid="5777075614321087758">"Nastavit"</string> @@ -1591,8 +1601,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Některé funkce nemusí být k dispozici"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Pokračujte klepnutím"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Uživatelský profil je uzamčen"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Připojeno k zařízení <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Klepnutím zobrazíte soubory"</string> + <string name="pin_target" msgid="3052256031352291362">"Připnout"</string> + <string name="unpin_target" msgid="3556545602439143442">"Odepnout"</string> + <string name="app_info" msgid="6856026610594615344">"Informace o aplikaci"</string> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 4cfdfce75673..4a3780ca84eb 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-kort blev tilføjet"</string> <string name="sim_added_message" msgid="7797975656153714319">"Genstart din enhed for at få adgang til mobilnetværket."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Genstart"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Du skal installere og åbne en app fra dit mobilselskab for at få dit nye SIM-kort til at fungere korrekt."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"HENT APPEN"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"IKKE NU"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Nyt SIM-kort er indsat"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Tryk for at konfigurere"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Angiv tidspunkt"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Angiv dato"</string> <string name="date_time_set" msgid="5777075614321087758">"Angiv"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Nogle funktioner er muligvis ikke tilgængelige"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Tryk for at fortsætte"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Brugerprofilen er låst"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Tilsluttet <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tryk for at se filer"</string> + <string name="pin_target" msgid="3052256031352291362">"Fastgør"</string> + <string name="unpin_target" msgid="3556545602439143442">"Frigør"</string> + <string name="app_info" msgid="6856026610594615344">"Oplysninger om appen"</string> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 26a8b8b78ace..f04521fc7265 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -191,7 +191,7 @@ <string name="reboot_to_update_prepare" msgid="6305853831955310890">"Aktualisierung wird vorbereitet…"</string> <string name="reboot_to_update_package" msgid="3871302324500927291">"Updatepaket wird verarbeitet…"</string> <string name="reboot_to_update_reboot" msgid="6428441000951565185">"Neustart…"</string> - <string name="reboot_to_reset_title" msgid="4142355915340627490">"Auf Werkszustand zurück"</string> + <string name="reboot_to_reset_title" msgid="4142355915340627490">"Auf Werkszustand zurücksetzen"</string> <string name="reboot_to_reset_message" msgid="2432077491101416345">"Neustart…"</string> <string name="shutdown_progress" msgid="2281079257329981203">"Wird heruntergefahren..."</string> <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Dein Tablet wird heruntergefahren."</string> @@ -926,7 +926,7 @@ <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> reagiert nicht"</string> <string name="anr_process" msgid="6156880875555921105">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> reagiert nicht"</string> <string name="force_close" msgid="8346072094521265605">"OK"</string> - <string name="report" msgid="4060218260984795706">"Bericht"</string> + <string name="report" msgid="4060218260984795706">"Melden"</string> <string name="wait" msgid="7147118217226317732">"Warten"</string> <string name="webpage_unresponsive" msgid="3272758351138122503">"Die Seite reagiert nicht mehr.\n\nMöchtest du die Seite schließen?"</string> <string name="launch_warning_title" msgid="1547997780506713581">"App umgeleitet"</string> @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-Karte hinzugefügt"</string> <string name="sim_added_message" msgid="7797975656153714319">"Starte zur Nutzung des Mobilfunknetzes dein Gerät neu."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Neu starten"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Damit deine neue SIM-Karte ordnungsgemäß funktioniert, musst du zuerst eine App deines Mobilfunkanbieters installieren und öffnen."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"APP HERUNTERLADEN"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"JETZT NICHT"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Neue SIM-Karte eingelegt"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Zum Einrichten tippen"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Uhrzeit festlegen"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Datum festlegen"</string> <string name="date_time_set" msgid="5777075614321087758">"Speichern"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Einige Funktionen sind evtl. nicht verfügbar"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Zum Fortfahren tippen"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Nutzerprofil gesperrt"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Verbunden mit <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Zum Ansehen der Dateien tippen"</string> + <string name="pin_target" msgid="3052256031352291362">"Markieren"</string> + <string name="unpin_target" msgid="3556545602439143442">"Markierung entfernen"</string> + <string name="app_info" msgid="6856026610594615344">"App-Informationen"</string> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index b1dfe0b03039..c557c7350c3f 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Προστέθηκε κάρτα SIM"</string> <string name="sim_added_message" msgid="7797975656153714319">"Επανεκκινήστε τη συσκευή σας, για να αποκτήσετε πρόσβαση στο δίκτυο κινητής τηλεφωνίας."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Επανεκκίνηση"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Για να λειτουργεί σωστά η νέα κάρτα SIM, θα πρέπει να εγκαταστήσετε και να ανοίξετε μια εφαρμογή από την εταιρεία κινητής τηλεφωνίας που χρησιμοποιείτε."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"ΛΗΨΗ ΤΗΣ ΕΦΑΡΜΟΓΗΣ"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"ΟΧΙ ΤΩΡΑ"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Τοποθετήθηκε νέα SIM"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Πατήστε για ρύθμιση"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Ρύθμιση ώρας"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Ορισμός ημερομηνίας"</string> <string name="date_time_set" msgid="5777075614321087758">"Ορισμός"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Ενδεχόμενο μη διαθέσιμων λειτουργιών"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Αγγίξτε για συνέχεια"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Το προφίλ χρήστη κλειδώθηκε"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Συνδέθηκε με το <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Πατήστε για να δείτε τα αρχεία"</string> + <string name="pin_target" msgid="3052256031352291362">"Καρφίτσωμα"</string> + <string name="unpin_target" msgid="3556545602439143442">"Ξεκαρφίτσωμα"</string> + <string name="app_info" msgid="6856026610594615344">"Πληροφορίες εφαρμογής"</string> </resources> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 9df47bd8af46..a0a5493af1cf 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM card added"</string> <string name="sim_added_message" msgid="7797975656153714319">"Restart your device to access the mobile network."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Restart"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"To get your new SIM working properly, you\'ll need to install and open an app from your operator."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"GET THE APP"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NOT NOW"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"New SIM inserted"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Tap to set it up"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Set time"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Set date"</string> <string name="date_time_set" msgid="5777075614321087758">"Set"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Some functions might not be available"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Touch to continue"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"User profile locked"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connected to <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tap to view files"</string> + <string name="pin_target" msgid="3052256031352291362">"Pin"</string> + <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string> + <string name="app_info" msgid="6856026610594615344">"App info"</string> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 9df47bd8af46..a0a5493af1cf 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM card added"</string> <string name="sim_added_message" msgid="7797975656153714319">"Restart your device to access the mobile network."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Restart"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"To get your new SIM working properly, you\'ll need to install and open an app from your operator."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"GET THE APP"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NOT NOW"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"New SIM inserted"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Tap to set it up"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Set time"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Set date"</string> <string name="date_time_set" msgid="5777075614321087758">"Set"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Some functions might not be available"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Touch to continue"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"User profile locked"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connected to <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tap to view files"</string> + <string name="pin_target" msgid="3052256031352291362">"Pin"</string> + <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string> + <string name="app_info" msgid="6856026610594615344">"App info"</string> </resources> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 9df47bd8af46..a0a5493af1cf 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM card added"</string> <string name="sim_added_message" msgid="7797975656153714319">"Restart your device to access the mobile network."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Restart"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"To get your new SIM working properly, you\'ll need to install and open an app from your operator."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"GET THE APP"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NOT NOW"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"New SIM inserted"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Tap to set it up"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Set time"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Set date"</string> <string name="date_time_set" msgid="5777075614321087758">"Set"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Some functions might not be available"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Touch to continue"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"User profile locked"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connected to <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tap to view files"</string> + <string name="pin_target" msgid="3052256031352291362">"Pin"</string> + <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string> + <string name="app_info" msgid="6856026610594615344">"App info"</string> </resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 5a2689cc0457..f07745bb4bff 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"Ninguna aplicación puede realizar esta acción."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> se detuvo"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> se detuvo"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> continúa fallando"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> continúa fallando"</string> <string name="aerr_restart" msgid="9001379185665886595">"Reiniciar app"</string> <string name="aerr_reset" msgid="7645427603514220451">"Restablecer y reiniciar la app"</string> <string name="aerr_report" msgid="5371800241488400617">"Enviar comentarios"</string> <string name="aerr_close" msgid="2991640326563991340">"Cerrar"</string> <string name="aerr_mute" msgid="7698966346654789433">"Silenciar"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Esperar"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Cerrar app"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> no responde"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no responde"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> no responde"</string> + <string name="anr_process" msgid="6156880875555921105">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no responde"</string> <string name="force_close" msgid="8346072094521265605">"Aceptar"</string> <string name="report" msgid="4060218260984795706">"Notificar"</string> <string name="wait" msgid="7147118217226317732">"Esperar"</string> @@ -1039,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Tarjeta SIM agregada"</string> <string name="sim_added_message" msgid="7797975656153714319">"Reinicia el dispositivo para acceder a la red móvil."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Para que tu SIM nueva funcione correctamente, debes instalar y abrir la app de tu proveedor."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"OBTENER LA APP"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"AHORA NO"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Nueva SIM insertada"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Presiona para configurar"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Configurar hora"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Configurar fecha"</string> <string name="date_time_set" msgid="5777075614321087758">"Establecer"</string> @@ -1470,10 +1467,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para quitar fijación"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicitar patrón de desbloqueo para quitar fijación"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicitar contraseña para quitar fijación"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"No se puede modificar el tamaño de la app. Desplázala con dos dedos."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"La app no es compatible con la función de pantalla dividida."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Lo instaló el administrador."</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por el administrador"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Lo eliminó el administrador."</string> @@ -1563,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Funciones no disponibles"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Tocar para continuar"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil de usuario bloqueado"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Presiona para ver archivos"</string> + <string name="pin_target" msgid="3052256031352291362">"Fijar"</string> + <string name="unpin_target" msgid="3556545602439143442">"No fijar"</string> + <string name="app_info" msgid="6856026610594615344">"Información de la app"</string> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 147d841f694c..518b1574244c 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Tarjeta SIM añadida"</string> <string name="sim_added_message" msgid="7797975656153714319">"Reinicia el dispositivo para acceder a la red móvil."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Para que tu nueva SIM funcione correctamente, debes instalar y abrir una aplicación de tu operador."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"DESCARGAR LA APLICACIÓN"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"AHORA NO"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Nueva SIM insertada"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Toca para configurar"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Establecer hora"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Establecer fecha"</string> <string name="date_time_set" msgid="5777075614321087758">"Establecer"</string> @@ -1557,8 +1562,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Algunas funciones no disponibles"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Toca para continuar"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil de usuario bloqueado"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toca para ver archivos"</string> + <string name="pin_target" msgid="3052256031352291362">"Fijar"</string> + <string name="unpin_target" msgid="3556545602439143442">"No fijar"</string> + <string name="app_info" msgid="6856026610594615344">"Información de la aplicación"</string> </resources> diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml index bcad12cf02f8..234892975128 100644 --- a/core/res/res/values-et-rEE/strings.xml +++ b/core/res/res/values-et-rEE/strings.xml @@ -1031,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-kaart lisatud"</string> <string name="sim_added_message" msgid="7797975656153714319">"Mobiilsidevõrku pääsemiseks taaskäivitage seade."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Taaskäivita"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Kellaaja määramine"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Kuupäeva määramine"</string> <string name="date_time_set" msgid="5777075614321087758">"Määra"</string> @@ -1553,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Mõni funktsioon pole võib-olla saadaval"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Puudutage jätkamiseks"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Kasutajaprofiil on lukustatud"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Ühendatud seadmega <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Failide vaatamiseks puudutage"</string> + <string name="pin_target" msgid="3052256031352291362">"Kinnita"</string> + <string name="unpin_target" msgid="3556545602439143442">"Vabasta"</string> + <string name="app_info" msgid="6856026610594615344">"Rakenduse teave"</string> </resources> diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml index d3e877c59cde..a595603f4775 100644 --- a/core/res/res/values-eu-rES/strings.xml +++ b/core/res/res/values-eu-rES/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM txartela gehitu da"</string> <string name="sim_added_message" msgid="7797975656153714319">"Sare mugikorra atzitzeko, berrabiarazi gailua."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Berrabiarazi"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"SIM berriak behar bezala funtziona dezan, operadorearen aplikazio bat instalatu eta ireki behar duzu."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"ESKURATU APLIKAZIOA"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"ORAIN EZ"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"SIM berria sartu da"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Sakatu konfiguratzeko"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Ezarri ordua"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Ezarri data"</string> <string name="date_time_set" msgid="5777075614321087758">"Ezarri"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Baliteke funtzio batzuk ez egotea"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Ukitu jarraitzeko"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Blokeatuta dago profila"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> zerbitzura konektatuta"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Sakatu fitxategiak ikusteko"</string> + <string name="pin_target" msgid="3052256031352291362">"Ainguratu"</string> + <string name="unpin_target" msgid="3556545602439143442">"Kendu aingura"</string> + <string name="app_info" msgid="6856026610594615344">"Aplikazioari buruzko informazioa"</string> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index c41eda496ca9..14b87e874349 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"سیم کارت اضافه شد"</string> <string name="sim_added_message" msgid="7797975656153714319">"برای دسترسی به شبکه تلفن همراه، دستگاهتان را مجدداً راهاندازی کنید."</string> <string name="sim_restart_button" msgid="4722407842815232347">"راهاندازی مجدد"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"برای اینکه سیمکارت جدیدتان عملکرد درستی داشته باشد باید برنامهای را از شرکت مخابراتیتان نصب و باز کنید."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"دریافت برنامه"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"اکنون نه"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"سیمکارت جدید جاگذاری شد"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"برای تنظیم آن ضربه بزنید"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"تنظیم زمان"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"تاریخ تنظیم"</string> <string name="date_time_set" msgid="5777075614321087758">"تنظیم"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"شاید برخی عملکردها دردسترس نباشند"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"برای ادامه لمس کنید"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"نمایه کاربر قفل است"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"به <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> متصل شد"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"برای دیدن فایلها، ضربه بزنید"</string> + <string name="pin_target" msgid="3052256031352291362">"پین کردن"</string> + <string name="unpin_target" msgid="3556545602439143442">"برداشتن پین"</string> + <string name="app_info" msgid="6856026610594615344">"اطلاعات برنامه"</string> </resources> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 4c115974c009..ff78c91f7e20 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"Yksikään sovellus ei voi suorittaa tätä toimintoa."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> pysähtyi."</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> pysähtyi."</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> pysähtyy toistuvasti."</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> pysähtyy toistuvasti."</string> <string name="aerr_restart" msgid="9001379185665886595">"Käynnistä sovellus uudelleen"</string> <string name="aerr_reset" msgid="7645427603514220451">"Nollaa sovellus ja käynnistä uudelleen"</string> <string name="aerr_report" msgid="5371800241488400617">"Lähetä palautetta"</string> <string name="aerr_close" msgid="2991640326563991340">"Sulje"</string> <string name="aerr_mute" msgid="7698966346654789433">"Ohita"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Odota"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Sulje sovellus"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> ei vastaa."</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei vastaa."</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> ei vastaa."</string> + <string name="anr_process" msgid="6156880875555921105">"Prosessi <xliff:g id="PROCESS">%1$s</xliff:g> ei vastaa."</string> <string name="force_close" msgid="8346072094521265605">"OK"</string> <string name="report" msgid="4060218260984795706">"Ilmoita"</string> <string name="wait" msgid="7147118217226317732">"Odota"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-kortti lisätty"</string> <string name="sim_added_message" msgid="7797975656153714319">"Käynnistä laite uudelleen, niin pääset käyttämään matkapuhelinverkkoa."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Käynnistä uudelleen"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Aseta aika"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Aseta päivämäärä"</string> <string name="date_time_set" msgid="5777075614321087758">"Aseta"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pyydä PIN ennen irrotusta"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pyydä lukituksenpoistokuvio ennen irrotusta"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pyydä salasana ennen irrotusta"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Sovelluksen kokoa ei voi muuttaa. Vieritä näkymää kahdella sormella."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Sovellus ei tue jaetun näytön tilaa."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Järjestelmänvalvoja on asentanut paketin."</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Järjestelmänvalvojasi on päivittänyt paketin."</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Järjestelmänvalvoja on poistanut paketin."</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Osaa toiminnoista ei ehkä voi käyttää"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Jatka koskettamalla."</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Käyttäjäprofiili on lukittu."</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> yhdistetty"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Näytä tiedostot koskettamalla"</string> + <string name="pin_target" msgid="3052256031352291362">"Kiinnitä"</string> + <string name="unpin_target" msgid="3556545602439143442">"Irrota"</string> + <string name="app_info" msgid="6856026610594615344">"Sovelluksen tiedot"</string> </resources> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index a366dbbffca8..1cef50aeb59f 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"Aucune application ne peut effectuer cette action."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> a cessé de fonctionner"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> a cessé de fonctionner"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> plante continuellement"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> plante continuellement"</string> <string name="aerr_restart" msgid="9001379185665886595">"Redémarrer l\'application"</string> <string name="aerr_reset" msgid="7645427603514220451">"Réinitialiser et redémarrer l\'application"</string> <string name="aerr_report" msgid="5371800241488400617">"Envoyer des commentaires"</string> <string name="aerr_close" msgid="2991640326563991340">"Fermer"</string> <string name="aerr_mute" msgid="7698966346654789433">"Désactiver les notifications"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Attendre"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Fermer l\'application"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> ne répond pas"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ne répond pas"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> ne répond pas"</string> + <string name="anr_process" msgid="6156880875555921105">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> ne répond pas"</string> <string name="force_close" msgid="8346072094521265605">"OK"</string> <string name="report" msgid="4060218260984795706">"Signaler"</string> <string name="wait" msgid="7147118217226317732">"Attendre"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"Carte SIM ajoutée."</string> <string name="sim_added_message" msgid="7797975656153714319">"Redémarrez votre appareil pour accéder au réseau cellulaire."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Recommencer"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Définir l\'heure"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Définir la date"</string> <string name="date_time_set" msgid="5777075614321087758">"Paramètres"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le NIP avant d\'annuler l\'épinglage"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Demander le mot de passe avant d\'annuler l\'épinglage"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Impossible de redimensionner l\'application. Faites-la défiler avec deux doigts."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"L\'application n\'est pas compatible avec l\'écran partagé."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Installé par votre administrateur"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Supprimé par votre administrateur"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Certaines fonct. p-ê non dispo."</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Touchez pour continuer"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profil d\'utilisateur verrouillé"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connecté à <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Touchez ici pour afficher les fichiers"</string> + <string name="pin_target" msgid="3052256031352291362">"Épingler"</string> + <string name="unpin_target" msgid="3556545602439143442">"Annuler l\'épinglage"</string> + <string name="app_info" msgid="6856026610594615344">"Détails de l\'application"</string> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index e275aeb88025..662076dff4c7 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Carte SIM ajoutée."</string> <string name="sim_added_message" msgid="7797975656153714319">"Redémarrez votre appareil pour accéder au réseau mobile."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Redémarrer"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Pour que la nouvelle carte SIM fonctionne correctement, vous devez installer et ouvrir une application fournie par votre opérateur."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"TÉLÉCHARGER L\'APPLICATION"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"PLUS TARD"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Nouvelle carte SIM insérée"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Appuyez ici pour effectuer la configuration."</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Définir l\'heure"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Définir la date"</string> <string name="date_time_set" msgid="5777075614321087758">"Définir"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Certaines fonctions potentiellement non dispos"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Appuyer pour continuer"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profil utilisateur verrouillé"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connecté à <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Appuyez ici pour voir les fichiers."</string> + <string name="pin_target" msgid="3052256031352291362">"Épingler"</string> + <string name="unpin_target" msgid="3556545602439143442">"Retirer"</string> + <string name="app_info" msgid="6856026610594615344">"Infos sur l\'appli"</string> </resources> diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml index d7acd73fc1b0..f2e1850bfd0f 100644 --- a/core/res/res/values-gl-rES/strings.xml +++ b/core/res/res/values-gl-rES/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Engadiuse unha tarxeta SIM"</string> <string name="sim_added_message" msgid="7797975656153714319">"Reinicia o teu dispositivo para acceder á rede móbil."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Para conseguir que a túa SIM nova funcione correctamente, deberás instalar e abrir unha aplicación do teu operador."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"DESCARGAR A APLICACIÓN"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"AGORA NON"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Introduciuse unha nova SIM"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Tocar para configurar"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Configurar hora"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Establecer data"</string> <string name="date_time_set" msgid="5777075614321087758">"Configurar"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Quizais haxa funcións non dispoñibles"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Toca para continuar"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Bloqueouse o perfil do usuario"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toca para ver os ficheiros"</string> + <string name="pin_target" msgid="3052256031352291362">"Fixar"</string> + <string name="unpin_target" msgid="3556545602439143442">"Soltar"</string> + <string name="app_info" msgid="6856026610594615344">"Información da aplicación"</string> </resources> diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml index 19eb33bc2568..ec613b096b9b 100644 --- a/core/res/res/values-gu-rIN/strings.xml +++ b/core/res/res/values-gu-rIN/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM કાર્ડ ઉમેર્યું"</string> <string name="sim_added_message" msgid="7797975656153714319">"સેલ્યુલર નેટવર્કને ઍક્સેસ કરવામાં તમારા ઉપકરણને પુનઃપ્રારંભ કરો."</string> <string name="sim_restart_button" msgid="4722407842815232347">"પુનઃપ્રારંભ કરો"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"તમારું નવું SIM ઠીકથી કામ કરે તે માટે, તમને તમારા કેરીઅર પરથી ઍપ્લિકેશન ઇન્સ્ટૉલ કરીને ખોલવી પડશે."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"ઍપ્લિકેશન મેળવો"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"હમણાં નહીં"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"નવું SIM દાખલ કર્યું"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"તેને સેટ કરવા માટે ટૅપ કરો"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"સમય સેટ કરો"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"તારીખ સેટ કરો"</string> <string name="date_time_set" msgid="5777075614321087758">"સેટ કરો"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"કેટલાક કાર્યો કદાચ ઉપલબ્ધ ન હોય"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"ચાલુ રાખવા માટે ટચ કરો"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"વપરાશકર્તા પ્રોફાઇલ લૉક કરી"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> થી કનેક્ટ કરેલું છે"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ફાઇલો જોવા માટે ટૅપ કરો"</string> + <string name="pin_target" msgid="3052256031352291362">"પિન કરો"</string> + <string name="unpin_target" msgid="3556545602439143442">"અનપિન કરો"</string> + <string name="app_info" msgid="6856026610594615344">"ઍપ્લિકેશન માહિતી"</string> </resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 3130abca275f..4c944c3095b8 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"सिम कार्ड जोड़ा गया"</string> <string name="sim_added_message" msgid="7797975656153714319">"सेल्युलर नेटवर्क एक्सेस करने के लिए अपना डिवाइस पुन: प्रारंभ करें."</string> <string name="sim_restart_button" msgid="4722407842815232347">"पुन: प्रारंभ करें"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"आपकी नई SIM ठीक से काम करे, इसके लिए आपको अपने वाहक से किसी ऐप को इंस्टॉल करना होगा और खोलना होगा."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"ऐप प्राप्त करें"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"अभी नहीं"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"नई SIM डाली गई"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"इसे सेट करने के लिए टैप करें"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"समय सेट करें"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"दिनांक सेट करें"</string> <string name="date_time_set" msgid="5777075614321087758">"सेट करें"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"संभवत: कुछ फंक्शन उपलब्ध न हों"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"जारी रखने के लिए स्पर्श करें"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"उपयोगकर्ता प्रोफ़ाइल लॉक है"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> से कनेक्ट किया गया"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"फ़ाइलें देखने के लिए टैप करें"</string> + <string name="pin_target" msgid="3052256031352291362">"पिन करें"</string> + <string name="unpin_target" msgid="3556545602439143442">"अनपिन करें"</string> + <string name="app_info" msgid="6856026610594615344">"ऐप की जानकारी"</string> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 81522028d003..407841fb06b3 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1039,6 +1039,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM kartica dodana"</string> <string name="sim_added_message" msgid="7797975656153714319">"Za pristup mobilnoj mreži ponovo pokrenite uređaj."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Ponovno pokreni"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Postavljanje vremena"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Postavi datum"</string> <string name="date_time_set" msgid="5777075614321087758">"Postavi"</string> @@ -1572,8 +1582,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Možda ima nedostupnih funkcija"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Dodirnite da biste nastavili"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Korisnički je profil zaključan"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> – veza je uspostavljena"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dodirnite da biste pregledali datoteke"</string> + <string name="pin_target" msgid="3052256031352291362">"Prikvači"</string> + <string name="unpin_target" msgid="3556545602439143442">"Otkvači"</string> + <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index c8c53d1b716d..22a9ac456dc6 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1031,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM kártya hozzáadva"</string> <string name="sim_added_message" msgid="7797975656153714319">"A mobilhálózat eléréséhez indítsa újra az eszközt."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Újraindítás"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Idő beállítása"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Dátum beállítása"</string> <string name="date_time_set" msgid="5777075614321087758">"Beállítás"</string> @@ -1553,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Néhány funkció nem használható"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Érintse meg a folytatáshoz"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Felhasználói profil zárolva"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Csatlakoztatva a(z) <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> eszközhöz"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Koppintson ide a fájlok megtekintéséhez"</string> + <string name="pin_target" msgid="3052256031352291362">"Rögzítés"</string> + <string name="unpin_target" msgid="3556545602439143442">"Feloldás"</string> + <string name="app_info" msgid="6856026610594615344">"Alkalmazásinformáció"</string> </resources> diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml index 49ea7fc5f11b..dfdabaa97093 100644 --- a/core/res/res/values-hy-rAM/strings.xml +++ b/core/res/res/values-hy-rAM/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"Ոչ մի հավելված չի կարող կատարել այս գործողությունը:"</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածի աշխատանքն ընդհատվել է"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> գործընթացն ընդհատվել է"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածի աշխատանքը շարունակաբար ընդհատվում է"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> գործընթացը շարունակաբար ընդհատվում է"</string> <string name="aerr_restart" msgid="9001379185665886595">"Վերագործարկել հավելվածը"</string> <string name="aerr_reset" msgid="7645427603514220451">"Վերակայել և վերագործարկել հավելվածը"</string> <string name="aerr_report" msgid="5371800241488400617">"Ուղարկել կարծիք"</string> <string name="aerr_close" msgid="2991640326563991340">"Փակել"</string> <string name="aerr_mute" msgid="7698966346654789433">"Անջատել ձայնը"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Սպասել"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Փակել հավելվածը"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածը չի արձագանքում"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> գործունեությունը չի արձագանքում"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածը չի արձագանքում"</string> + <string name="anr_process" msgid="6156880875555921105">"<xliff:g id="PROCESS">%1$s</xliff:g> գործընթացը չի արձագանքում"</string> <string name="force_close" msgid="8346072094521265605">"Լավ"</string> <string name="report" msgid="4060218260984795706">"Զեկույց"</string> <string name="wait" msgid="7147118217226317732">"Սպասեք"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM քարտը ավելացվել է"</string> <string name="sim_added_message" msgid="7797975656153714319">"Վերագործարկեք ձեր սարքը` բջջային ցանց մուտք ունենալու համար:"</string> <string name="sim_restart_button" msgid="4722407842815232347">"Վերագործարկել"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Սահմանել ժամը"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Սահմանել ամսաթիվը"</string> <string name="date_time_set" msgid="5777075614321087758">"Սահմանել"</string> @@ -1216,7 +1218,7 @@ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Ընտրել ծրագիր"</string> <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Չհաջողվեց գործարկել <xliff:g id="APPLICATION_NAME">%s</xliff:g> ծրագիրը"</string> <string name="shareactionprovider_share_with" msgid="806688056141131819">"Տարածել"</string> - <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Համօգտագործել <xliff:g id="APPLICATION_NAME">%s</xliff:g>-ի հետ"</string> + <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Կիսվել <xliff:g id="APPLICATION_NAME">%s</xliff:g>-ի հետ"</string> <string name="content_description_sliding_handle" msgid="415975056159262248">"Սահող բռնակ: Հպել & պահել:"</string> <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Սահեցրեք` ապակողպելու համար:"</string> <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Միացրեք ականջակալները` արտասանվող գաղտնաբառը լսելու համար:"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ապաամրացնելուց առաջ հարցնել PIN-կոդը"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ապաամրացնելուց առաջ հարցնել ապակողպող նախշը"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ապաամրացնելուց առաջ հարցնել գաղտնաբառը"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Հավելվածի չափը հնարավոր չէ փոխել, ոլորեք այն երկու մատի օգնությամբ:"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Հավելվածը չի աջակցում էկրանի տրոհումը:"</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Ադմինիստրատորը տեղադրել է այն"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Ադմինիստրատորը թարմացրել է այն"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Ադմինիստրատորը ջնջել է այն"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Հնարավոր է՝ որոշ գործառույթներ հասանելի չլինեն"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Հպեք՝ շարունակելու համար"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Օգտվողի պրոֆիլը կողպված է"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Միացված է <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>-ին"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Հպեք՝ ֆայլերը տեսնելու համար"</string> + <string name="pin_target" msgid="3052256031352291362">"Ամրացնել"</string> + <string name="unpin_target" msgid="3556545602439143442">"Ապամրացնել"</string> + <string name="app_info" msgid="6856026610594615344">"Հավելվածի տվյալներ"</string> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 9f488f4b9425..4d4f45e1dd44 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Kartu SIM ditambahkan"</string> <string name="sim_added_message" msgid="7797975656153714319">"Mulai ulang perangkat untuk mengakses jaringan seluler."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Mulai Ulang"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Agar SIM baru bekerja dengan baik, Anda harus memasang dan membuka aplikasi dari operator."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"DAPATKAN APLIKASI"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"LAIN KALI"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"SIM baru dimasukkan"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Ketuk untuk menyiapkan"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Setel waktu"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Setel tanggal"</string> <string name="date_time_set" msgid="5777075614321087758">"Setel"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Beberapa fungsi tidak ada"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Sentuh untuk melanjutkan"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profil pengguna terkunci"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Tersambung ke <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Ketuk untuk melihat file"</string> + <string name="pin_target" msgid="3052256031352291362">"Pasang pin"</string> + <string name="unpin_target" msgid="3556545602439143442">"Lepas pin"</string> + <string name="app_info" msgid="6856026610594615344">"Info aplikasi"</string> </resources> diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml index 7c388478d7ff..4ad48a943b0f 100644 --- a/core/res/res/values-is-rIS/strings.xml +++ b/core/res/res/values-is-rIS/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"Engin forrit geta framkvæmt þessa aðgerð."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> stöðvaðist"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> stöðvaðist"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> stöðvast ítrekað"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> stöðvast ítrekað"</string> <string name="aerr_restart" msgid="9001379185665886595">"Endurræsa forritið"</string> <string name="aerr_reset" msgid="7645427603514220451">"Endurstilla og endurræsa forritið"</string> <string name="aerr_report" msgid="5371800241488400617">"Senda ábendingu"</string> <string name="aerr_close" msgid="2991640326563991340">"Loka"</string> <string name="aerr_mute" msgid="7698966346654789433">"Þagga"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Bíða"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Loka forriti"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> svarar ekki"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> svarar ekki"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> svarar ekki"</string> + <string name="anr_process" msgid="6156880875555921105">"Vinnslan <xliff:g id="PROCESS">%1$s</xliff:g> svarar ekki"</string> <string name="force_close" msgid="8346072094521265605">"Í lagi"</string> <string name="report" msgid="4060218260984795706">"Tilkynna"</string> <string name="wait" msgid="7147118217226317732">"Bíða"</string> @@ -1039,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-korti bætt við"</string> <string name="sim_added_message" msgid="7797975656153714319">"Endurræstu tækið til að tengjast farsímakerfinu."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Endurræsa"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Þú þarft að setja upp og opna forrit frá símafyrirtækinu þínu til að nýja SIM-kortið þitt virki eins og vera ber."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"SÆKJA FORRITIÐ"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"EKKI NÚNA"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Nýtt SIM-kort sett í"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Ýttu til að setja það upp"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Veldu tíma"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Veldu dagsetningu"</string> <string name="date_time_set" msgid="5777075614321087758">"Velja"</string> @@ -1470,10 +1467,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Biðja um PIN-númer til að losa"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Biðja um opnunarmynstur til að losa"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Biðja um aðgangsorð til að losa"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Ekki er hægt að breyta stærð forritsins; flettu upp og niður með tveimur fingrum."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Forritið styður ekki að skjánum sé skipt."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Uppsett af kerfisstjóra"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Uppfært af kerfisstjóranum"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eytt af kerfisstjóra"</string> @@ -1563,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Sumir eiginleikar e.t.v. ekki í boði"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Snertu til að halda áfram"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Notandaprófíll læstur"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Tengt við <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Ýttu til að skoða skrárnar"</string> + <string name="pin_target" msgid="3052256031352291362">"Festa"</string> + <string name="unpin_target" msgid="3556545602439143442">"Losa"</string> + <string name="app_info" msgid="6856026610594615344">"Forritsupplýsingar"</string> </resources> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index eb0bd940509d..88bbf5617206 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Scheda SIM aggiunta"</string> <string name="sim_added_message" msgid="7797975656153714319">"Riavvia il dispositivo per accedere alla rete cellulare."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Riavvia"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Per far funzionare correttamente la tua nuova SIM, dovrai installare e aprire un\'app del tuo operatore."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"SCARICA L\'APP"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NON ORA"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Nuova SIM inserita"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Tocca per configurarla"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Imposta ora"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Imposta data"</string> <string name="date_time_set" msgid="5777075614321087758">"Imposta"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Alcune funzioni potrebbero non essere disponibili"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Tocca per continuare"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profilo utente bloccato"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Connesso a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tocca per visualizzare i file"</string> + <string name="pin_target" msgid="3052256031352291362">"Blocca"</string> + <string name="unpin_target" msgid="3556545602439143442">"Sblocca"</string> + <string name="app_info" msgid="6856026610594615344">"Informazioni app"</string> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index a4942d7cdb79..ffdfdab6dc84 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1047,6 +1047,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"כרטיס ה-SIM נוסף"</string> <string name="sim_added_message" msgid="7797975656153714319">"אתחל את המכשיר כדי לגשת אל הרשת הסלולרית."</string> <string name="sim_restart_button" msgid="4722407842815232347">"הפעל מחדש"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"הגדרת שעה"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"הגדר תאריך"</string> <string name="date_time_set" msgid="5777075614321087758">"הגדר"</string> @@ -1591,8 +1601,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"ייתכן שפונקציות מסוימות לא יהיו זמינות"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"גע כדי להמשיך"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"פרופיל המשתמש נעול"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"מחובר אל <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"הקש כדי להציג קבצים"</string> + <string name="pin_target" msgid="3052256031352291362">"הצמד"</string> + <string name="unpin_target" msgid="3556545602439143442">"בטל הצמדה"</string> + <string name="app_info" msgid="6856026610594615344">"פרטי אפליקציה"</string> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 01779ad4590f..7dc7653a7cbb 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1032,6 +1032,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIMカードが追加されました"</string> <string name="sim_added_message" msgid="7797975656153714319">"モバイルネットワークにアクセスするには端末を再起動してください。"</string> <string name="sim_restart_button" msgid="4722407842815232347">"再起動"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"時刻設定"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"日付設定"</string> <string name="date_time_set" msgid="5777075614321087758">"設定"</string> @@ -1559,8 +1569,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"一部の機能が利用できない可能性"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"続行するにはタップしてください"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"ユーザー プロフィールはロックされています"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> に接続しました"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"タップしてファイルを表示"</string> + <string name="pin_target" msgid="3052256031352291362">"固定"</string> + <string name="unpin_target" msgid="3556545602439143442">"固定を解除"</string> + <string name="app_info" msgid="6856026610594615344">"アプリ情報"</string> </resources> diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml index f26c32bddace..be172aa66d9d 100644 --- a/core/res/res/values-ka-rGE/strings.xml +++ b/core/res/res/values-ka-rGE/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"ვერც ერთი აპი ვერ შეასრულებს ამ ქმედებას."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> შეჩერდა"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> შეწყდა"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> განუწყვეტლივ ჩერდება"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> განუწყვეტლივ წყდება"</string> <string name="aerr_restart" msgid="9001379185665886595">"აპის გადატვირთვა"</string> <string name="aerr_reset" msgid="7645427603514220451">"გადაყენება და აპის გადატვირთვა"</string> <string name="aerr_report" msgid="5371800241488400617">"გამოხმაურება"</string> <string name="aerr_close" msgid="2991640326563991340">"დახურვა"</string> <string name="aerr_mute" msgid="7698966346654789433">"დადუმება"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"მოცდა"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"აპის დახურვა"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> არ რეაგირებს"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> არ რეაგირებს"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> არ რეაგირებს"</string> + <string name="anr_process" msgid="6156880875555921105">"პროცესი — <xliff:g id="PROCESS">%1$s</xliff:g> არ რეაგირებს"</string> <string name="force_close" msgid="8346072094521265605">"OK"</string> <string name="report" msgid="4060218260984795706">"ანგარიში"</string> <string name="wait" msgid="7147118217226317732">"მოცდა"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM ბარათი დაემატა"</string> <string name="sim_added_message" msgid="7797975656153714319">"გადატვირთეთ თქვენი მოწყობილობა ფიჭურ ქსელზე წვდომისთვის."</string> <string name="sim_restart_button" msgid="4722407842815232347">"გადატვირთვა"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"დროის დაყენება"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"თარიღის დაყენება"</string> <string name="date_time_set" msgid="5777075614321087758">"დაყენება"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ფიქსაციის მოხსნამდე PIN-ის მოთხოვნა"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ფიქსაციის მოხსნამდე განბლოკვის ნიმუშის მოთხოვნა"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ფიქსაციის მოხსნამდე პაროლის მოთხოვნა"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"აპის ზომა ვერ შეიცვლება. გადაადგილდით მასში ორი თითის მეშვეობით."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"თქვენი ადმინისტრატორის მიერ დაყენებული"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"თქვენი ადმინისტრატორის მიერ წაშლილი"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"ზოგიერთი ფუნქცია შეიძლება მიუწვდომელი იყოს"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"შეეხეთ გასაგრძელებლად"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"მომხმარებლის პროფილი ჩაკეტილია"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"დაკავშირებულია <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>-თან"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"შეეხეთ ფაილების სანახავად"</string> + <string name="pin_target" msgid="3052256031352291362">"ჩამაგრება"</string> + <string name="unpin_target" msgid="3556545602439143442">"ჩამაგრების მოხსნა"</string> + <string name="app_info" msgid="6856026610594615344">"აპის შესახებ"</string> </resources> diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml index f583c9f9de88..a9eecd97f0ca 100644 --- a/core/res/res/values-kk-rKZ/strings.xml +++ b/core/res/res/values-kk-rKZ/strings.xml @@ -1031,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM картасы қосылды"</string> <string name="sim_added_message" msgid="7797975656153714319">"Ұялы желіге қатынасу үшін құрылғыны қайта іске қосыңыз."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Қайта бастау"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Уақытты реттеу"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Мезгілін реттеу"</string> <string name="date_time_set" msgid="5777075614321087758">"Орнату"</string> @@ -1553,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Кейбір функциялар қол жетімді болмауы мүмкін"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Жалғастыру үшін түртіңіз"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Пайдаланушы профилі құлыпталған"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> қосылу орындалды"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Файлдарды көру үшін түртіңіз"</string> + <string name="pin_target" msgid="3052256031352291362">"PIN код"</string> + <string name="unpin_target" msgid="3556545602439143442">"Босату"</string> + <string name="app_info" msgid="6856026610594615344">"Қолданба ақпараты"</string> </resources> diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml index 150b5724afc2..4dbb28381483 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -1033,6 +1033,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"បានបន្ថែមស៊ីមកាត"</string> <string name="sim_added_message" msgid="7797975656153714319">"ចាប់ផ្ដើមឧបករណ៍របស់អ្នកឡើងវិញ ដើម្បីចូលប្រើបណ្ដាញចល័ត។"</string> <string name="sim_restart_button" msgid="4722407842815232347">"ចាប់ផ្ដើមឡើងវិញ"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"កំណត់ម៉ោង"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"កំណត់កាលបរិច្ឆេទ"</string> <string name="date_time_set" msgid="5777075614321087758">"កំណត់"</string> @@ -1555,8 +1565,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"មុខងារមួយចំនួនមិនអាចប្រើបានទេ"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"ប៉ះដើម្បីបន្ត"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"ប្រវត្តិរូបអ្នកប្រើត្រូវបានចាក់សោ"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"បានភ្ជាប់ទៅ <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ប៉ះដើម្បីមើលឯកសារ"</string> + <string name="pin_target" msgid="3052256031352291362">"ខ្ទាស់"</string> + <string name="unpin_target" msgid="3556545602439143442">"មិនខ្ទាស់"</string> + <string name="app_info" msgid="6856026610594615344">"ព័ត៌មានកម្មវិធី"</string> </resources> diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml index f13e77e31c55..d251f82a4a50 100644 --- a/core/res/res/values-kn-rIN/strings.xml +++ b/core/res/res/values-kn-rIN/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"ಸಿಮ್ ಕಾರ್ಡ್ ಸೇರಿಸಲಾಗಿದೆ"</string> <string name="sim_added_message" msgid="7797975656153714319">"ಸೆಲ್ಯುಲಾರ್ ನೆಟ್ವರ್ಕ್ ಪ್ರವೇಶಿಸಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿ."</string> <string name="sim_restart_button" msgid="4722407842815232347">"ಮರುಪ್ರಾರಂಭಿಸು"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"ನಿಮ್ಮ ಹೊಸ ಸಿಮ್ ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡಲು, ನಿಮ್ಮ ವಾಹಕದಿಂದ ಒಂದು ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ನೀವು ಸ್ಥಾಪಿಸಬೇಕಾಗುತ್ತದೆ ಮತ್ತು ತೆರೆಯಬೇಕಾಗುತ್ತದೆ."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"ಅಪ್ಲಿಕೇಶನ್ ಪಡೆದುಕೊಳ್ಳಿ"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"ಈಗ ಬೇಡ"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"ಹೊಸ ಸಿಮ್ ಸೇರಿಸಲಾಗಿದೆ"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"ಇದನ್ನು ಸ್ಥಾಪಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"ಸಮಯವನ್ನು ಹೊಂದಿಸಿ"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"ದಿನಾಂಕವನ್ನು ಹೊಂದಿಸಿ"</string> <string name="date_time_set" msgid="5777075614321087758">"ಹೊಂದಿಸು"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"ಕೆಲವು ಫಂಕ್ಷನ್ಗಳು ಲಭ್ಯವಿಲ್ಲದಿರಬಹುದು"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"ಮುಂದುವರಿಸಲು ಸ್ಪರ್ಶಿಸಿ"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"ಬಳಕೆದಾರ ಪ್ರೊಫೈಲ್ ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ಫೈಲ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> + <string name="pin_target" msgid="3052256031352291362">"ಪಿನ್ ಮಾಡು"</string> + <string name="unpin_target" msgid="3556545602439143442">"ಅನ್ಪಿನ್"</string> + <string name="app_info" msgid="6856026610594615344">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 04304bf71f4d..6f725aae3db4 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"작업을 수행할 수 있는 앱이 없습니다."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g>이(가) 중지됨"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g>이(가) 중지됨"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g>이(가) 계속 중단됨"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g>이(가) 계속 중단됨"</string> <string name="aerr_restart" msgid="9001379185665886595">"앱 다시 시작"</string> <string name="aerr_reset" msgid="7645427603514220451">"앱 재설정 및 다시 시작"</string> <string name="aerr_report" msgid="5371800241488400617">"의견 보내기"</string> <string name="aerr_close" msgid="2991640326563991340">"닫기"</string> <string name="aerr_mute" msgid="7698966346654789433">"숨기기"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"대기"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"앱 닫기"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g>이(가) 응답하지 않음"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g>이(가) 응답하지 않음"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g>이(가) 응답하지 않음"</string> + <string name="anr_process" msgid="6156880875555921105">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 응답하지 않음"</string> <string name="force_close" msgid="8346072094521265605">"확인"</string> <string name="report" msgid="4060218260984795706">"신고"</string> <string name="wait" msgid="7147118217226317732">"대기"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM 카드 추가됨"</string> <string name="sim_added_message" msgid="7797975656153714319">"이동통신망에 액세스하려면 기기를 다시 시작하세요."</string> <string name="sim_restart_button" msgid="4722407842815232347">"다시 시작"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"시간 설정"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"날짜 설정"</string> <string name="date_time_set" msgid="5777075614321087758">"설정"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"고정 해제 이전에 PIN 요청"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"고정 해제 이전에 잠금해제 패턴 요청"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"고정 해제 이전에 비밀번호 요청"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"앱에서 크기 조절이 불가능합니다. 두 손가락을 사용해 스크롤하세요."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"앱이 화면 분할을 지원하지 않습니다."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"관리자가 설치함"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"관리자에 의해 업데이트됨"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"관리자가 삭제함"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"일부 기능을 사용할 수 없음"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"계속하려면 터치하세요."</string> <string name="user_encrypted_detail" msgid="979981584766912935">"사용자 프로필이 잠겨 있습니다."</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>에 연결됨"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"파일을 확인하려면 탭하세요."</string> + <string name="pin_target" msgid="3052256031352291362">"고정"</string> + <string name="unpin_target" msgid="3556545602439143442">"고정 해제"</string> + <string name="app_info" msgid="6856026610594615344">"앱 정보"</string> </resources> diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml index 9ec79ccff7e2..6b6145edcaca 100644 --- a/core/res/res/values-ky-rKG/strings.xml +++ b/core/res/res/values-ky-rKG/strings.xml @@ -232,7 +232,7 @@ <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмундар жашырылган"</string> - <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Саясат тарабынан жашырылган мазмундар"</string> + <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Тийиштүү саясат боюнча жашырылган мазмундар"</string> <string name="safeMode" msgid="2788228061547930246">"Коопсуз режим"</string> <string name="android_system_label" msgid="6577375335728551336">"Android Тутуму"</string> <string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string> @@ -912,28 +912,20 @@ <string name="noApplications" msgid="2991814273936504689">"Бул аракетти аткара турган колдонмо жок."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> токтотулду"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> токтотулду"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> кайра эле токтотулууда"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> кайра эле токтотулууда"</string> <string name="aerr_restart" msgid="9001379185665886595">"Колдонмону кайра жүргүзүү"</string> <string name="aerr_reset" msgid="7645427603514220451">"Колдонмону баштапкы абалга келтирип, кайра жүргүзүү"</string> <string name="aerr_report" msgid="5371800241488400617">"Жооп пикир жөнөтүү"</string> <string name="aerr_close" msgid="2991640326563991340">"Жабуу"</string> <string name="aerr_mute" msgid="7698966346654789433">"Үнсүз"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Күтүү"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Колдонмону жабуу"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> жооп бербей жатат"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> жооп бербей жатат"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> жооп бербей жатат"</string> + <string name="anr_process" msgid="6156880875555921105">"<xliff:g id="PROCESS">%1$s</xliff:g> процесси жооп бербей жатат"</string> <string name="force_close" msgid="8346072094521265605">"OK"</string> <string name="report" msgid="4060218260984795706">"Кабарлоо"</string> <string name="wait" msgid="7147118217226317732">"Күтүү"</string> @@ -1040,6 +1032,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-карта кошулду"</string> <string name="sim_added_message" msgid="7797975656153714319">"Уюктук тармакка кирүү үчүн түзмөгүңүздү өчүрүп күйгүзүңүз."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Кайра баштоо"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Убакыт орнотуу"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Күнүн орнотуу"</string> <string name="date_time_set" msgid="5777075614321087758">"Коюу"</string> @@ -1471,10 +1473,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Бошотуудан мурун PIN суралсын"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Бошотуудан мурун кулпуну ачкан үлгү суралсын"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Бошотуудан мурун сырсөз суралсын"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Колдонмонун көлөмүн өзгөртүүгө болбойт, андыктан эки манжаңыз менен сыдырып караңыз."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Колдонмо экранды бөлүүнү колдобойт."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Администраторуңуз тарабынан орнотулган"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Администраторуңуз жаңырткан"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Администраторуңуз тарабынан жок кылынган"</string> @@ -1547,7 +1547,7 @@ <string name="importance_from_topic" msgid="3572280439880023233">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string> <string name="importance_from_person" msgid="9160133597262938296">"Булар сиз үчүн маанилүү адамдар."</string> <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби ?"</string> - <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби (мындай каттоо эсеби менен колдонуучу мурунтан эле бар) ?"</string> + <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби (мындай каттоо эсеби бар колдонуучу мурунтан эле бар) ?"</string> <string name="language_selection_title" msgid="7181332986330337171">"Тил жөндөөлөрү"</string> <string name="country_selection_title" msgid="2954859441620215513">"Чөлкөмдүк жөндөөлөр"</string> <string name="search_language_hint" msgid="7042102592055108574">"Тилди киргизиңиз"</string> @@ -1564,8 +1564,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Айрым функциялар иштбши мүмкн"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Улантуу үчүн тийип коюңуз"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Колдонуучнн профили кулпулнгн"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> менен туташты"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Файлдарды көрүү үчүн таптап коюңуз"</string> + <string name="pin_target" msgid="3052256031352291362">"Кадоо"</string> + <string name="unpin_target" msgid="3556545602439143442">"Кадоодон алып коюу"</string> + <string name="app_info" msgid="6856026610594615344">"Колдонмо тууралуу"</string> </resources> diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml index 01ccd698b159..2e0a6ad38c35 100644 --- a/core/res/res/values-lo-rLA/strings.xml +++ b/core/res/res/values-lo-rLA/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"ບໍ່ມີແອັບຯໃດສາມາດເຮັດວຽກນີ້ໄດ້."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> ໄດ້ຢຸດແລ້ວ"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> ໄດ້ຢຸດແລ້ວ"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> ຢຸດເລື້ອຍໆ"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> ຢຸດເລື້ອຍໆ"</string> <string name="aerr_restart" msgid="9001379185665886595">"ເລີ່ມແອັບໃໝ່"</string> <string name="aerr_reset" msgid="7645427603514220451">"ຣີເຊັດ ແລະ ເລີ່ມແອັບໃໝ່"</string> <string name="aerr_report" msgid="5371800241488400617">"ສົ່ງຄຳຕິຊົມ"</string> <string name="aerr_close" msgid="2991640326563991340">"ປິດ"</string> <string name="aerr_mute" msgid="7698966346654789433">"ປິດສຽງ"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"ລໍຖ້າ"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"ປິດແອັບ"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> ບໍ່ຕອບສະໜອງ"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ບໍ່ຕອບສະໜອງ"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> ບໍ່ຕອບສະໜອງ"</string> + <string name="anr_process" msgid="6156880875555921105">"ຂະບວນການ <xliff:g id="PROCESS">%1$s</xliff:g> ບໍ່ຕອບສະໜອງ"</string> <string name="force_close" msgid="8346072094521265605">"ຕົກລົງ"</string> <string name="report" msgid="4060218260984795706">"ລາຍງານ"</string> <string name="wait" msgid="7147118217226317732">"ລໍຖ້າ"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"ເພີ່ມຊິມກາດແລ້ວ"</string> <string name="sim_added_message" msgid="7797975656153714319">"ຣີສະຕາດອຸປະກອນຂອງທ່ານເພື່ອເຂົ້າເຖິງເຄືອຂ່າຍມືຖື."</string> <string name="sim_restart_button" msgid="4722407842815232347">"ຣີສະຕາດ"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"ຕັ້ງເວລາ"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"ກໍານົດວັນທີ"</string> <string name="date_time_set" msgid="5777075614321087758">"ຕັ້ງຄ່າ"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ຖາມຫາ PIN ກ່ອນຍົກເລີກການປັກໝຸດ"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ຖາມຫາຮູບແບບປົດລັອກກ່ອນຍົກເລີກການປັກໝຸດ"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ຖາມຫາລະຫັດຜ່ານກ່ອນຍົກເລີກການປັກໝຸດ"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ບໍ່ສາມາດປັບຂະໜາດແອັບໄດ້, ໃຫ້ເລື່ອນມັນໂດຍໃຊ້ນິ້ວມືສອງນິ້ວ."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ແອັບບໍ່ຮອງຮັບໜ້າຈໍແບບແຍກກັນ."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"ຜູ້ຄວບຄຸມຂອງທ່ານຕິດຕັ້ງໃສ່ແລ້ວ"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"ອັບເດດໂດຍຜູ້ຄວບຄຸມຂອງທ່ານແລ້ວ"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"ຖືກຜູ້ຄວບຄຸມຂອງທ່ານລຶບໄປແລ້ວ"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"ບາງຟັງຊັນອາດບໍ່ສາມາດໃຊ້ໄດ້"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"ແຕະເພື່ອສືບຕໍ່"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"ໂປຣໄຟລ໌ຜູ້ໃຊ້ຖືກລັອກໄວ້ແລ້ວ"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"ເຊື່ອມຕໍ່ກັບ <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ແລ້ວ"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ແຕະເພື່ອເບິ່ງໄຟລ໌"</string> + <string name="pin_target" msgid="3052256031352291362">"ປັກໝຸດ"</string> + <string name="unpin_target" msgid="3556545602439143442">"ຖອນປັກໝຸດ"</string> + <string name="app_info" msgid="6856026610594615344">"ຂໍ້ມູນແອັບ"</string> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 0d0a4ede3cd1..698cebe8dc61 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1047,6 +1047,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM kortelė pridėta"</string> <string name="sim_added_message" msgid="7797975656153714319">"Iš naujo paleiskite įrenginį, kad pasiektumėte korinį tinklą."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Paleisti iš naujo"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Kad nauja SIM kortelė veiktų tinkamai, turite įdiegti ir atidaryti iš operatoriaus gautą programą."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"GAUTI PROGRAMĄ"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NE DABAR"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Įdėta nauja SIM kortelė"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Jei norite tai nustatyti, palieskite"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Nustatyti laiką"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Nustatyti datą"</string> <string name="date_time_set" msgid="5777075614321087758">"Nustatyti"</string> @@ -1591,8 +1596,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Kelios funkc. gali būti nepas."</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Jei norite tęsti, palieskite"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Naudotojo profilis užrakintas"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Prisijungta prie „<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>“"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Palieskite, kad peržiūrėtumėte failus"</string> + <string name="pin_target" msgid="3052256031352291362">"Prisegti"</string> + <string name="unpin_target" msgid="3556545602439143442">"Atsegti"</string> + <string name="app_info" msgid="6856026610594615344">"Programos informacija"</string> </resources> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index c8754bfbfc2c..8c0081bf27f6 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1039,6 +1039,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM karte ir pievienota."</string> <string name="sim_added_message" msgid="7797975656153714319">"Lai piekļūtu mobilajam tīklam, restartējiet ierīci."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Restartēt"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Iestatīt laiku"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Datuma iestatīšana"</string> <string name="date_time_set" msgid="5777075614321087758">"Iestatīt"</string> @@ -1572,8 +1582,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Dažas funkcijas var nebūt pieejamas"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Pieskarieties, lai turpinātu."</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Lietotāja profils ir bloķēts."</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Izveidots savienojums ar: <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Pieskarieties, lai skatītu failus."</string> + <string name="pin_target" msgid="3052256031352291362">"Piespraust"</string> + <string name="unpin_target" msgid="3556545602439143442">"Atspraust"</string> + <string name="app_info" msgid="6856026610594615344">"Lietotnes informācija"</string> </resources> diff --git a/core/res/res/values-mcc310-mnc200-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc200-az-rAZ/strings.xml new file mode 100644 index 000000000000..94e7f8888fd4 --- /dev/null +++ b/core/res/res/values-mcc310-mnc200-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9107329079910661798">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2841003137832065541">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6806975706640442517">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc200-es/strings.xml b/core/res/res/values-mcc310-mnc200-es/strings.xml new file mode 100644 index 000000000000..9ec401a74ad3 --- /dev/null +++ b/core/res/res/values-mcc310-mnc200-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9107329079910661798">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2841003137832065541">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6806975706640442517">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc200-hi/strings.xml b/core/res/res/values-mcc310-mnc200-hi/strings.xml new file mode 100644 index 000000000000..1d8272ad1603 --- /dev/null +++ b/core/res/res/values-mcc310-mnc200-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9107329079910661798">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2841003137832065541">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6806975706640442517">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc200-in/strings.xml b/core/res/res/values-mcc310-mnc200-in/strings.xml new file mode 100644 index 000000000000..c71dbf721acf --- /dev/null +++ b/core/res/res/values-mcc310-mnc200-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9107329079910661798">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2841003137832065541">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6806975706640442517">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc200-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc200-mr-rIN/strings.xml new file mode 100644 index 000000000000..fc89cfca8551 --- /dev/null +++ b/core/res/res/values-mcc310-mnc200-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9107329079910661798">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2841003137832065541">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6806975706640442517">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc200-nl/strings.xml b/core/res/res/values-mcc310-mnc200-nl/strings.xml new file mode 100644 index 000000000000..22f8de25bc44 --- /dev/null +++ b/core/res/res/values-mcc310-mnc200-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9107329079910661798">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2841003137832065541">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6806975706640442517">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc200-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc200-pa-rIN/strings.xml new file mode 100644 index 000000000000..0083af30640b --- /dev/null +++ b/core/res/res/values-mcc310-mnc200-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9107329079910661798">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2841003137832065541">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6806975706640442517">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc200-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc200-pt-rPT/strings.xml new file mode 100644 index 000000000000..530b065b20a5 --- /dev/null +++ b/core/res/res/values-mcc310-mnc200-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9107329079910661798">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2841003137832065541">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6806975706640442517">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc200-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc200-te-rIN/strings.xml new file mode 100644 index 000000000000..85f29eecd08b --- /dev/null +++ b/core/res/res/values-mcc310-mnc200-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9107329079910661798">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2841003137832065541">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6806975706640442517">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc200-zu/strings.xml b/core/res/res/values-mcc310-mnc200-zu/strings.xml new file mode 100644 index 000000000000..f4209a633b67 --- /dev/null +++ b/core/res/res/values-mcc310-mnc200-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9107329079910661798">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-Fi, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-Fi futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2841003137832065541">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6806975706640442517">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc210-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc210-az-rAZ/strings.xml new file mode 100644 index 000000000000..6a818359c61b --- /dev/null +++ b/core/res/res/values-mcc310-mnc210-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="5217754856196352581">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4688475512286389971">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5475635312889002673">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc210-es/strings.xml b/core/res/res/values-mcc310-mnc210-es/strings.xml new file mode 100644 index 000000000000..8fe5eba15927 --- /dev/null +++ b/core/res/res/values-mcc310-mnc210-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="5217754856196352581">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4688475512286389971">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5475635312889002673">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc210-hi/strings.xml b/core/res/res/values-mcc310-mnc210-hi/strings.xml new file mode 100644 index 000000000000..b560f048e4d2 --- /dev/null +++ b/core/res/res/values-mcc310-mnc210-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="5217754856196352581">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4688475512286389971">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5475635312889002673">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc210-in/strings.xml b/core/res/res/values-mcc310-mnc210-in/strings.xml new file mode 100644 index 000000000000..264bb51b14b1 --- /dev/null +++ b/core/res/res/values-mcc310-mnc210-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="5217754856196352581">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4688475512286389971">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5475635312889002673">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc210-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc210-mr-rIN/strings.xml new file mode 100644 index 000000000000..1d2958552f85 --- /dev/null +++ b/core/res/res/values-mcc310-mnc210-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="5217754856196352581">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4688475512286389971">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5475635312889002673">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc210-nl/strings.xml b/core/res/res/values-mcc310-mnc210-nl/strings.xml new file mode 100644 index 000000000000..d90df1267167 --- /dev/null +++ b/core/res/res/values-mcc310-mnc210-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="5217754856196352581">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4688475512286389971">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5475635312889002673">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc210-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc210-pa-rIN/strings.xml new file mode 100644 index 000000000000..39bdd6405934 --- /dev/null +++ b/core/res/res/values-mcc310-mnc210-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="5217754856196352581">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4688475512286389971">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5475635312889002673">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc210-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc210-pt-rPT/strings.xml new file mode 100644 index 000000000000..173d97daeff9 --- /dev/null +++ b/core/res/res/values-mcc310-mnc210-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="5217754856196352581">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4688475512286389971">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5475635312889002673">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc210-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc210-te-rIN/strings.xml new file mode 100644 index 000000000000..d3141d8540c0 --- /dev/null +++ b/core/res/res/values-mcc310-mnc210-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="5217754856196352581">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4688475512286389971">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5475635312889002673">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc210-zu/strings.xml b/core/res/res/values-mcc310-mnc210-zu/strings.xml new file mode 100644 index 000000000000..cde0a8c73820 --- /dev/null +++ b/core/res/res/values-mcc310-mnc210-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="5217754856196352581">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-Fi, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-Fi futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4688475512286389971">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5475635312889002673">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc220-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc220-az-rAZ/strings.xml new file mode 100644 index 000000000000..e169bc23736f --- /dev/null +++ b/core/res/res/values-mcc310-mnc220-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6238990105876016549">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2866631708941520085">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="3422704506272221128">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc220-es/strings.xml b/core/res/res/values-mcc310-mnc220-es/strings.xml new file mode 100644 index 000000000000..5292afee270e --- /dev/null +++ b/core/res/res/values-mcc310-mnc220-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6238990105876016549">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2866631708941520085">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="3422704506272221128">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc220-hi/strings.xml b/core/res/res/values-mcc310-mnc220-hi/strings.xml new file mode 100644 index 000000000000..d1e7bd26e7af --- /dev/null +++ b/core/res/res/values-mcc310-mnc220-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6238990105876016549">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2866631708941520085">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="3422704506272221128">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc220-in/strings.xml b/core/res/res/values-mcc310-mnc220-in/strings.xml new file mode 100644 index 000000000000..075d2ef508ee --- /dev/null +++ b/core/res/res/values-mcc310-mnc220-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6238990105876016549">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2866631708941520085">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="3422704506272221128">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc220-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc220-mr-rIN/strings.xml new file mode 100644 index 000000000000..c40186458e51 --- /dev/null +++ b/core/res/res/values-mcc310-mnc220-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6238990105876016549">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2866631708941520085">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="3422704506272221128">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc220-nl/strings.xml b/core/res/res/values-mcc310-mnc220-nl/strings.xml new file mode 100644 index 000000000000..ed37e20e5020 --- /dev/null +++ b/core/res/res/values-mcc310-mnc220-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6238990105876016549">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2866631708941520085">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="3422704506272221128">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc220-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc220-pa-rIN/strings.xml new file mode 100644 index 000000000000..0da091d59911 --- /dev/null +++ b/core/res/res/values-mcc310-mnc220-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6238990105876016549">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2866631708941520085">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="3422704506272221128">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc220-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc220-pt-rPT/strings.xml new file mode 100644 index 000000000000..4fcb1787e57f --- /dev/null +++ b/core/res/res/values-mcc310-mnc220-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6238990105876016549">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2866631708941520085">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="3422704506272221128">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc220-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc220-te-rIN/strings.xml new file mode 100644 index 000000000000..3529f932ee17 --- /dev/null +++ b/core/res/res/values-mcc310-mnc220-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6238990105876016549">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2866631708941520085">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="3422704506272221128">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc220-zu/strings.xml b/core/res/res/values-mcc310-mnc220-zu/strings.xml new file mode 100644 index 000000000000..f0c0f6af1983 --- /dev/null +++ b/core/res/res/values-mcc310-mnc220-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6238990105876016549">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-Fi, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-Fi futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="2866631708941520085">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="3422704506272221128">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc230-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc230-az-rAZ/strings.xml new file mode 100644 index 000000000000..f85048a63e40 --- /dev/null +++ b/core/res/res/values-mcc310-mnc230-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9007462326786949889">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="6747587721329739803">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="903741468703044544">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc230-es/strings.xml b/core/res/res/values-mcc310-mnc230-es/strings.xml new file mode 100644 index 000000000000..034e47f9d9ac --- /dev/null +++ b/core/res/res/values-mcc310-mnc230-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9007462326786949889">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="6747587721329739803">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="903741468703044544">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc230-hi/strings.xml b/core/res/res/values-mcc310-mnc230-hi/strings.xml new file mode 100644 index 000000000000..61cdf58a201e --- /dev/null +++ b/core/res/res/values-mcc310-mnc230-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9007462326786949889">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="6747587721329739803">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="903741468703044544">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc230-in/strings.xml b/core/res/res/values-mcc310-mnc230-in/strings.xml new file mode 100644 index 000000000000..d385771ed9b4 --- /dev/null +++ b/core/res/res/values-mcc310-mnc230-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9007462326786949889">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="6747587721329739803">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="903741468703044544">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc230-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc230-mr-rIN/strings.xml new file mode 100644 index 000000000000..008a2cc13fa0 --- /dev/null +++ b/core/res/res/values-mcc310-mnc230-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9007462326786949889">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="6747587721329739803">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="903741468703044544">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc230-nl/strings.xml b/core/res/res/values-mcc310-mnc230-nl/strings.xml new file mode 100644 index 000000000000..157bd3c96ec9 --- /dev/null +++ b/core/res/res/values-mcc310-mnc230-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9007462326786949889">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="6747587721329739803">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="903741468703044544">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc230-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc230-pa-rIN/strings.xml new file mode 100644 index 000000000000..20160e812eee --- /dev/null +++ b/core/res/res/values-mcc310-mnc230-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9007462326786949889">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="6747587721329739803">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="903741468703044544">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc230-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc230-pt-rPT/strings.xml new file mode 100644 index 000000000000..d253f8f1898e --- /dev/null +++ b/core/res/res/values-mcc310-mnc230-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9007462326786949889">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="6747587721329739803">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="903741468703044544">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc230-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc230-te-rIN/strings.xml new file mode 100644 index 000000000000..f14c57438c19 --- /dev/null +++ b/core/res/res/values-mcc310-mnc230-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9007462326786949889">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="6747587721329739803">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="903741468703044544">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc230-zu/strings.xml b/core/res/res/values-mcc310-mnc230-zu/strings.xml new file mode 100644 index 000000000000..0b043d0e6ef8 --- /dev/null +++ b/core/res/res/values-mcc310-mnc230-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="9007462326786949889">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-Fi, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-Fi futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="6747587721329739803">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="903741468703044544">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc240-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc240-az-rAZ/strings.xml new file mode 100644 index 000000000000..84575b65d7fe --- /dev/null +++ b/core/res/res/values-mcc310-mnc240-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2734345662112241986">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5561711399459051107">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6383482961309785661">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc240-es/strings.xml b/core/res/res/values-mcc310-mnc240-es/strings.xml new file mode 100644 index 000000000000..29b80aaabad4 --- /dev/null +++ b/core/res/res/values-mcc310-mnc240-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2734345662112241986">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5561711399459051107">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6383482961309785661">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc240-hi/strings.xml b/core/res/res/values-mcc310-mnc240-hi/strings.xml new file mode 100644 index 000000000000..90531375bece --- /dev/null +++ b/core/res/res/values-mcc310-mnc240-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2734345662112241986">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5561711399459051107">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6383482961309785661">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc240-in/strings.xml b/core/res/res/values-mcc310-mnc240-in/strings.xml new file mode 100644 index 000000000000..2d17f2071ab7 --- /dev/null +++ b/core/res/res/values-mcc310-mnc240-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2734345662112241986">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5561711399459051107">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6383482961309785661">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc240-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc240-mr-rIN/strings.xml new file mode 100644 index 000000000000..d9ffd6350099 --- /dev/null +++ b/core/res/res/values-mcc310-mnc240-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2734345662112241986">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5561711399459051107">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6383482961309785661">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc240-nl/strings.xml b/core/res/res/values-mcc310-mnc240-nl/strings.xml new file mode 100644 index 000000000000..c35dc6abeaf0 --- /dev/null +++ b/core/res/res/values-mcc310-mnc240-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2734345662112241986">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5561711399459051107">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6383482961309785661">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc240-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc240-pa-rIN/strings.xml new file mode 100644 index 000000000000..0f1b5bcac857 --- /dev/null +++ b/core/res/res/values-mcc310-mnc240-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2734345662112241986">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5561711399459051107">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6383482961309785661">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc240-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc240-pt-rPT/strings.xml new file mode 100644 index 000000000000..af0550547354 --- /dev/null +++ b/core/res/res/values-mcc310-mnc240-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2734345662112241986">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5561711399459051107">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6383482961309785661">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc240-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc240-te-rIN/strings.xml new file mode 100644 index 000000000000..ccace1af9736 --- /dev/null +++ b/core/res/res/values-mcc310-mnc240-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2734345662112241986">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5561711399459051107">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6383482961309785661">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc240-zu/strings.xml b/core/res/res/values-mcc310-mnc240-zu/strings.xml new file mode 100644 index 000000000000..9aa62d358b42 --- /dev/null +++ b/core/res/res/values-mcc310-mnc240-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2734345662112241986">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-Fi, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-Fi futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5561711399459051107">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="6383482961309785661">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc250-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc250-az-rAZ/strings.xml new file mode 100644 index 000000000000..fb70ba858127 --- /dev/null +++ b/core/res/res/values-mcc310-mnc250-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="3177110876268966">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5743977848030289234">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1221554601313232001">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc250-es/strings.xml b/core/res/res/values-mcc310-mnc250-es/strings.xml new file mode 100644 index 000000000000..afe979da3ac8 --- /dev/null +++ b/core/res/res/values-mcc310-mnc250-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="3177110876268966">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5743977848030289234">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1221554601313232001">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc250-hi/strings.xml b/core/res/res/values-mcc310-mnc250-hi/strings.xml new file mode 100644 index 000000000000..46c756bbf275 --- /dev/null +++ b/core/res/res/values-mcc310-mnc250-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="3177110876268966">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5743977848030289234">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1221554601313232001">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc250-in/strings.xml b/core/res/res/values-mcc310-mnc250-in/strings.xml new file mode 100644 index 000000000000..b1d5024421fe --- /dev/null +++ b/core/res/res/values-mcc310-mnc250-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="3177110876268966">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5743977848030289234">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1221554601313232001">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc250-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc250-mr-rIN/strings.xml new file mode 100644 index 000000000000..a2a10e10a19a --- /dev/null +++ b/core/res/res/values-mcc310-mnc250-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="3177110876268966">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5743977848030289234">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1221554601313232001">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc250-nl/strings.xml b/core/res/res/values-mcc310-mnc250-nl/strings.xml new file mode 100644 index 000000000000..f356b49ee68c --- /dev/null +++ b/core/res/res/values-mcc310-mnc250-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="3177110876268966">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5743977848030289234">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1221554601313232001">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc250-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc250-pa-rIN/strings.xml new file mode 100644 index 000000000000..29bac711a61c --- /dev/null +++ b/core/res/res/values-mcc310-mnc250-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="3177110876268966">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5743977848030289234">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1221554601313232001">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc250-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc250-pt-rPT/strings.xml new file mode 100644 index 000000000000..47482606478e --- /dev/null +++ b/core/res/res/values-mcc310-mnc250-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="3177110876268966">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5743977848030289234">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1221554601313232001">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc250-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc250-te-rIN/strings.xml new file mode 100644 index 000000000000..81e7e3c843d3 --- /dev/null +++ b/core/res/res/values-mcc310-mnc250-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="3177110876268966">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5743977848030289234">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1221554601313232001">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc250-zu/strings.xml b/core/res/res/values-mcc310-mnc250-zu/strings.xml new file mode 100644 index 000000000000..fc845e79e099 --- /dev/null +++ b/core/res/res/values-mcc310-mnc250-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="3177110876268966">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-Fi, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-Fi futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5743977848030289234">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1221554601313232001">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc270-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc270-az-rAZ/strings.xml new file mode 100644 index 000000000000..71e7a8a8d9e2 --- /dev/null +++ b/core/res/res/values-mcc310-mnc270-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6674750523418536585">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5880767641285399402">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5634367913183683816">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc270-es/strings.xml b/core/res/res/values-mcc310-mnc270-es/strings.xml new file mode 100644 index 000000000000..733412ad8922 --- /dev/null +++ b/core/res/res/values-mcc310-mnc270-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6674750523418536585">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5880767641285399402">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5634367913183683816">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc270-hi/strings.xml b/core/res/res/values-mcc310-mnc270-hi/strings.xml new file mode 100644 index 000000000000..c91d0b5ac751 --- /dev/null +++ b/core/res/res/values-mcc310-mnc270-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6674750523418536585">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5880767641285399402">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5634367913183683816">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc270-in/strings.xml b/core/res/res/values-mcc310-mnc270-in/strings.xml new file mode 100644 index 000000000000..67edf3ccf9fb --- /dev/null +++ b/core/res/res/values-mcc310-mnc270-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6674750523418536585">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5880767641285399402">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5634367913183683816">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc270-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc270-mr-rIN/strings.xml new file mode 100644 index 000000000000..650735cfab14 --- /dev/null +++ b/core/res/res/values-mcc310-mnc270-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6674750523418536585">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5880767641285399402">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5634367913183683816">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc270-nl/strings.xml b/core/res/res/values-mcc310-mnc270-nl/strings.xml new file mode 100644 index 000000000000..fd4957c749ed --- /dev/null +++ b/core/res/res/values-mcc310-mnc270-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6674750523418536585">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5880767641285399402">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5634367913183683816">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc270-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc270-pa-rIN/strings.xml new file mode 100644 index 000000000000..d17c01f7bd57 --- /dev/null +++ b/core/res/res/values-mcc310-mnc270-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6674750523418536585">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5880767641285399402">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5634367913183683816">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc270-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc270-pt-rPT/strings.xml new file mode 100644 index 000000000000..09a8dcbd6375 --- /dev/null +++ b/core/res/res/values-mcc310-mnc270-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6674750523418536585">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5880767641285399402">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5634367913183683816">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc270-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc270-te-rIN/strings.xml new file mode 100644 index 000000000000..d103e222704f --- /dev/null +++ b/core/res/res/values-mcc310-mnc270-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6674750523418536585">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5880767641285399402">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5634367913183683816">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc270-zu/strings.xml b/core/res/res/values-mcc310-mnc270-zu/strings.xml new file mode 100644 index 000000000000..49a203732572 --- /dev/null +++ b/core/res/res/values-mcc310-mnc270-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="6674750523418536585">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-Fi, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-Fi futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5880767641285399402">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="5634367913183683816">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc310-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc310-az-rAZ/strings.xml new file mode 100644 index 000000000000..0748e91fe501 --- /dev/null +++ b/core/res/res/values-mcc310-mnc310-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="1972026366984640493">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="1383416528714661108">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="7770475174975527040">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc310-es/strings.xml b/core/res/res/values-mcc310-mnc310-es/strings.xml new file mode 100644 index 000000000000..6dd980b5657d --- /dev/null +++ b/core/res/res/values-mcc310-mnc310-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="1972026366984640493">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="1383416528714661108">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="7770475174975527040">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc310-hi/strings.xml b/core/res/res/values-mcc310-mnc310-hi/strings.xml new file mode 100644 index 000000000000..611ec9c4d934 --- /dev/null +++ b/core/res/res/values-mcc310-mnc310-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="1972026366984640493">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="1383416528714661108">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="7770475174975527040">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc310-in/strings.xml b/core/res/res/values-mcc310-mnc310-in/strings.xml new file mode 100644 index 000000000000..e65f2658f089 --- /dev/null +++ b/core/res/res/values-mcc310-mnc310-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="1972026366984640493">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="1383416528714661108">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="7770475174975527040">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc310-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc310-mr-rIN/strings.xml new file mode 100644 index 000000000000..ce76a49c0bec --- /dev/null +++ b/core/res/res/values-mcc310-mnc310-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="1972026366984640493">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="1383416528714661108">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="7770475174975527040">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc310-nl/strings.xml b/core/res/res/values-mcc310-mnc310-nl/strings.xml new file mode 100644 index 000000000000..0266e3d597cb --- /dev/null +++ b/core/res/res/values-mcc310-mnc310-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="1972026366984640493">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="1383416528714661108">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="7770475174975527040">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc310-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc310-pa-rIN/strings.xml new file mode 100644 index 000000000000..7e9b8a48cd4f --- /dev/null +++ b/core/res/res/values-mcc310-mnc310-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="1972026366984640493">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="1383416528714661108">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="7770475174975527040">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc310-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc310-pt-rPT/strings.xml new file mode 100644 index 000000000000..e782c43d76db --- /dev/null +++ b/core/res/res/values-mcc310-mnc310-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="1972026366984640493">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="1383416528714661108">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="7770475174975527040">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc310-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc310-te-rIN/strings.xml new file mode 100644 index 000000000000..01613427d04f --- /dev/null +++ b/core/res/res/values-mcc310-mnc310-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="1972026366984640493">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="1383416528714661108">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="7770475174975527040">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc310-zu/strings.xml b/core/res/res/values-mcc310-mnc310-zu/strings.xml new file mode 100644 index 000000000000..465ee60e7b21 --- /dev/null +++ b/core/res/res/values-mcc310-mnc310-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="1972026366984640493">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-Fi, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-Fi futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="1383416528714661108">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="7770475174975527040">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc490-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc490-az-rAZ/strings.xml new file mode 100644 index 000000000000..e74d24755bff --- /dev/null +++ b/core/res/res/values-mcc310-mnc490-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2780619740658228275">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4633656294483906293">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1518868466785799436">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc490-es/strings.xml b/core/res/res/values-mcc310-mnc490-es/strings.xml new file mode 100644 index 000000000000..949fabba0833 --- /dev/null +++ b/core/res/res/values-mcc310-mnc490-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2780619740658228275">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4633656294483906293">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1518868466785799436">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc490-hi/strings.xml b/core/res/res/values-mcc310-mnc490-hi/strings.xml new file mode 100644 index 000000000000..27f5351e0496 --- /dev/null +++ b/core/res/res/values-mcc310-mnc490-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2780619740658228275">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4633656294483906293">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1518868466785799436">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc490-in/strings.xml b/core/res/res/values-mcc310-mnc490-in/strings.xml new file mode 100644 index 000000000000..4ae2c34e6701 --- /dev/null +++ b/core/res/res/values-mcc310-mnc490-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2780619740658228275">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4633656294483906293">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1518868466785799436">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc490-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc490-mr-rIN/strings.xml new file mode 100644 index 000000000000..25564bd860b1 --- /dev/null +++ b/core/res/res/values-mcc310-mnc490-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2780619740658228275">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4633656294483906293">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1518868466785799436">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc490-nl/strings.xml b/core/res/res/values-mcc310-mnc490-nl/strings.xml new file mode 100644 index 000000000000..27c41cfc949a --- /dev/null +++ b/core/res/res/values-mcc310-mnc490-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2780619740658228275">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4633656294483906293">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1518868466785799436">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc490-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc490-pa-rIN/strings.xml new file mode 100644 index 000000000000..39142f0b9454 --- /dev/null +++ b/core/res/res/values-mcc310-mnc490-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2780619740658228275">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4633656294483906293">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1518868466785799436">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc490-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc490-pt-rPT/strings.xml new file mode 100644 index 000000000000..743348b0e872 --- /dev/null +++ b/core/res/res/values-mcc310-mnc490-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2780619740658228275">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4633656294483906293">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1518868466785799436">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc490-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc490-te-rIN/strings.xml new file mode 100644 index 000000000000..a7ec75336c19 --- /dev/null +++ b/core/res/res/values-mcc310-mnc490-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2780619740658228275">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4633656294483906293">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1518868466785799436">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc490-zu/strings.xml b/core/res/res/values-mcc310-mnc490-zu/strings.xml new file mode 100644 index 000000000000..f8468b79f602 --- /dev/null +++ b/core/res/res/values-mcc310-mnc490-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="2780619740658228275">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-Fi, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-Fi futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="4633656294483906293">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="1518868466785799436">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc660-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc660-az-rAZ/strings.xml new file mode 100644 index 000000000000..24d9da37bd94 --- /dev/null +++ b/core/res/res/values-mcc310-mnc660-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="4027376374798357928">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5536938168415300276">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="979929705672330">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc660-es/strings.xml b/core/res/res/values-mcc310-mnc660-es/strings.xml new file mode 100644 index 000000000000..1c107efc054f --- /dev/null +++ b/core/res/res/values-mcc310-mnc660-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="4027376374798357928">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5536938168415300276">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="979929705672330">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc660-hi/strings.xml b/core/res/res/values-mcc310-mnc660-hi/strings.xml new file mode 100644 index 000000000000..487af6708571 --- /dev/null +++ b/core/res/res/values-mcc310-mnc660-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="4027376374798357928">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5536938168415300276">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="979929705672330">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc660-in/strings.xml b/core/res/res/values-mcc310-mnc660-in/strings.xml new file mode 100644 index 000000000000..a894b4cc1ab3 --- /dev/null +++ b/core/res/res/values-mcc310-mnc660-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="4027376374798357928">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5536938168415300276">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="979929705672330">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc660-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc660-mr-rIN/strings.xml new file mode 100644 index 000000000000..34a8182e3e82 --- /dev/null +++ b/core/res/res/values-mcc310-mnc660-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="4027376374798357928">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5536938168415300276">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="979929705672330">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc660-nl/strings.xml b/core/res/res/values-mcc310-mnc660-nl/strings.xml new file mode 100644 index 000000000000..100d7fc02810 --- /dev/null +++ b/core/res/res/values-mcc310-mnc660-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="4027376374798357928">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5536938168415300276">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="979929705672330">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc660-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc660-pa-rIN/strings.xml new file mode 100644 index 000000000000..57fc35e798d4 --- /dev/null +++ b/core/res/res/values-mcc310-mnc660-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="4027376374798357928">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5536938168415300276">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="979929705672330">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc660-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc660-pt-rPT/strings.xml new file mode 100644 index 000000000000..39b1ec15d070 --- /dev/null +++ b/core/res/res/values-mcc310-mnc660-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="4027376374798357928">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5536938168415300276">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="979929705672330">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc660-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc660-te-rIN/strings.xml new file mode 100644 index 000000000000..ac3c8916e98c --- /dev/null +++ b/core/res/res/values-mcc310-mnc660-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="4027376374798357928">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5536938168415300276">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="979929705672330">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc660-zu/strings.xml b/core/res/res/values-mcc310-mnc660-zu/strings.xml new file mode 100644 index 000000000000..9ee70dfb9a97 --- /dev/null +++ b/core/res/res/values-mcc310-mnc660-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="4027376374798357928">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-FI, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-FI futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="5536938168415300276">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="979929705672330">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc800-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc800-az-rAZ/strings.xml new file mode 100644 index 000000000000..ac2fec35e0ed --- /dev/null +++ b/core/res/res/values-mcc310-mnc800-az-rAZ/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="8435554129271297367">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="8993797655078232716">"Operatorla qeydiyyatdan keçin"</item> + </string-array> + <string name="wfcSpnFormat" msgid="8604078859021657352">"%s Wi-Fi Zəngi"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc800-es/strings.xml b/core/res/res/values-mcc310-mnc800-es/strings.xml new file mode 100644 index 000000000000..ca19be345aa3 --- /dev/null +++ b/core/res/res/values-mcc310-mnc800-es/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="8435554129271297367">"Para hacer llamadas y enviar mensajes por Wi-Fi, solicita a tu operador que configure este servicio y, cuando lo haga, vuelve a activar las llamadas por Wi-Fi en Ajustes."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="8993797655078232716">"Regístrate con tu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="8604078859021657352">"Llamada por Wi-Fi de %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc800-hi/strings.xml b/core/res/res/values-mcc310-mnc800-hi/strings.xml new file mode 100644 index 000000000000..c2b121b8e32e --- /dev/null +++ b/core/res/res/values-mcc310-mnc800-hi/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="8435554129271297367">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="8993797655078232716">"अपने वाहक के साथ पंजीकृत करें"</item> + </string-array> + <string name="wfcSpnFormat" msgid="8604078859021657352">"%s वाई-फ़ाई कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc800-in/strings.xml b/core/res/res/values-mcc310-mnc800-in/strings.xml new file mode 100644 index 000000000000..52b1f6ed4c0b --- /dev/null +++ b/core/res/res/values-mcc310-mnc800-in/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="8435554129271297367">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="8993797655078232716">"Harap daftarkan ke operator"</item> + </string-array> + <string name="wfcSpnFormat" msgid="8604078859021657352">"Panggilan Wi-Fi %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc800-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc800-mr-rIN/strings.xml new file mode 100644 index 000000000000..1f360d573739 --- /dev/null +++ b/core/res/res/values-mcc310-mnc800-mr-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="8435554129271297367">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="8993797655078232716">"आपल्या वाहकासह नोंदणी करा"</item> + </string-array> + <string name="wfcSpnFormat" msgid="8604078859021657352">"%s वाय-फाय कॉलिंग"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc800-nl/strings.xml b/core/res/res/values-mcc310-mnc800-nl/strings.xml new file mode 100644 index 000000000000..b87fce95fb5e --- /dev/null +++ b/core/res/res/values-mcc310-mnc800-nl/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="8435554129271297367">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via Instellingen."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="8993797655078232716">"Registreren bij je provider"</item> + </string-array> + <string name="wfcSpnFormat" msgid="8604078859021657352">"Bellen via wifi van %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc800-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc800-pa-rIN/strings.xml new file mode 100644 index 000000000000..5923eba2136c --- /dev/null +++ b/core/res/res/values-mcc310-mnc800-pa-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="8435554129271297367">"Wi-Fi \'ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈੱਟ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਤੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="8993797655078232716">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> + </string-array> + <string name="wfcSpnFormat" msgid="8604078859021657352">"%s Wi-Fi ਕਾਲਿੰਗ"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc800-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc800-pt-rPT/strings.xml new file mode 100644 index 000000000000..1ff0681e35e9 --- /dev/null +++ b/core/res/res/values-mcc310-mnc800-pt-rPT/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="8435554129271297367">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="8993797655078232716">"Registar-se junto do seu operador"</item> + </string-array> + <string name="wfcSpnFormat" msgid="8604078859021657352">"Chamadas Wi-Fi da %s"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc800-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc800-te-rIN/strings.xml new file mode 100644 index 000000000000..28bba73c0ec9 --- /dev/null +++ b/core/res/res/values-mcc310-mnc800-te-rIN/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="8435554129271297367">"Wi-Fiలో కాల్లు చేయడానికి మరియు సందేశాలు పంపడానికి, ముందుగా ఈ సేవను సెటప్ చేయమని మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="8993797655078232716">"మీ క్యారియర్తో నమోదు చేయండి"</item> + </string-array> + <string name="wfcSpnFormat" msgid="8604078859021657352">"%s Wi-Fi కాలింగ్"</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc800-zu/strings.xml b/core/res/res/values-mcc310-mnc800-zu/strings.xml new file mode 100644 index 000000000000..1335ac5e41fe --- /dev/null +++ b/core/res/res/values-mcc310-mnc800-zu/strings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You my 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. +*/ + --> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string-array name="wfcOperatorErrorAlertMessages"> + <item msgid="8435554129271297367">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-FI, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-FI futhi kusukela kuzilungiselelo."</item> + </string-array> + <string-array name="wfcOperatorErrorNotificationMessages"> + <item msgid="8993797655078232716">"Bhalisa ngenkampani yakho yenethiwekhi"</item> + </string-array> + <string name="wfcSpnFormat" msgid="8604078859021657352">"%s ukushaya kwe-Wi-Fi"</string> +</resources> diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml index 0e45601ed187..d67d78d15aa6 100644 --- a/core/res/res/values-mk-rMK/strings.xml +++ b/core/res/res/values-mk-rMK/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Додадена е СИМ картичка"</string> <string name="sim_added_message" msgid="7797975656153714319">"Рестартирајте го уредот за да пристапите кон мобилна мрежа."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Рестартирај"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"За да работи правилно вашата нова СИМ-картичка, треба да ја инсталирате и да ја отворите апликацијата од операторот."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"ПРЕЗЕМИ ЈА АПЛИКАЦИЈАТА"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"НЕ СЕГА"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Вметната е нова СИМ-картичка"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Допрете за да поставите"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Подеси време"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Постави датум"</string> <string name="date_time_set" msgid="5777075614321087758">"Подеси"</string> @@ -1555,8 +1560,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Некои функции се недостапни"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Допрете за да продолжите"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Корисничкиот профил е заклучен"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Поврзан на <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Допрете за да ги погледнете датотеките"</string> + <string name="pin_target" msgid="3052256031352291362">"Прикачете"</string> + <string name="unpin_target" msgid="3556545602439143442">"Откачете"</string> + <string name="app_info" msgid="6856026610594615344">"Информации за апликација"</string> </resources> diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml index afa11f842efe..4054577c251a 100644 --- a/core/res/res/values-ml-rIN/strings.xml +++ b/core/res/res/values-ml-rIN/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"അപ്ലിക്കേഷനുകൾക്കൊന്നും ഈ പ്രവർത്തനം നിർവഹിക്കാനാവില്ല."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> നിലച്ചിരിക്കുന്നു"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> നിലച്ചിരിക്കുന്നു"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> നിലയ്ക്കുന്നത് തുടരുന്നു"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> നിലയ്ക്കുന്നത് തുടരുന്നു"</string> <string name="aerr_restart" msgid="9001379185665886595">"ആപ്പ് പുനഃരാരംഭിക്കുക"</string> <string name="aerr_reset" msgid="7645427603514220451">"ആപ്പ് പുനഃക്രമീകരിച്ച് പുനഃരാരംഭിക്കുക"</string> <string name="aerr_report" msgid="5371800241488400617">"ഫീഡ്ബാക്ക് അയയ്ക്കുക"</string> <string name="aerr_close" msgid="2991640326563991340">"അടയ്ക്കുക"</string> <string name="aerr_mute" msgid="7698966346654789433">"മ്യൂട്ടുചെയ്യുക"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"കാത്തിരിക്കുക"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"ആപ്പ് അടയ്ക്കുക"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> പ്രതികരിക്കുന്നില്ല"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> പ്രതികരിക്കുന്നില്ല"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> പ്രതികരിക്കുന്നില്ല"</string> + <string name="anr_process" msgid="6156880875555921105">"<xliff:g id="PROCESS">%1$s</xliff:g> എന്ന പ്രോസസ്സ് പ്രതികരിക്കുന്നില്ല"</string> <string name="force_close" msgid="8346072094521265605">"ശരി"</string> <string name="report" msgid="4060218260984795706">"റിപ്പോര്ട്ടുചെയ്യുക"</string> <string name="wait" msgid="7147118217226317732">"കാത്തിരിക്കുക"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"സിം കാർഡ് ചേർത്തു"</string> <string name="sim_added_message" msgid="7797975656153714319">"സെല്ലുലാർ നെറ്റ്വർക്ക് ആക്സസ്സുചെയ്യാൻ നിങ്ങളുടെ ഉപകരണം പുനരാരംഭിക്കുക."</string> <string name="sim_restart_button" msgid="4722407842815232347">"പുനരാരംഭിക്കുക"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"സമയം സജ്ജീകരിക്കുക"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"ദിവസം സജ്ജീകരിക്കുക"</string> <string name="date_time_set" msgid="5777075614321087758">"സജ്ജമാക്കുക"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ചെയ്യുംമുമ്പ് പിൻ ചോദിക്കൂ"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് അൺലോക്ക് പാറ്റേൺ ആവശ്യപ്പെടുക"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് പാസ്വേഡ് ആവശ്യപ്പെടുക"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ആപ്പിന്റെ വലുപ്പം ക്രമീകരിക്കാൻ കഴിയില്ല, രണ്ട് വിരലുകൾ ഉപയോഗിച്ച് അത് സ്ക്രോൾ ചെയ്യുക."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"നിങ്ങളുടെ അഡ്മിനിസ്ട്രേറ്റർ ഇൻസ്റ്റാളുചെയ്തു"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"നിങ്ങളുടെ അഡ്മിനിസ്ട്രേറ്റർ അപ്ഡേറ്റുചെയ്തു"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"നിങ്ങളുടെ അഡ്മിനിസ്ട്രേറ്റർ ഇല്ലാതാക്കി"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"ചില ഫംഗ്ഷനുകൾ ലഭ്യമായേക്കില്ല"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"തുടരുന്നതിന് സ്പർശിക്കുക"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"ഉപയോക്തൃ പ്രൊഫൈൽ ലോക്കുചെയ്തു"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്തു"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ഫയലുകൾ കാണുന്നതിന് ടാപ്പുചെയ്യുക"</string> + <string name="pin_target" msgid="3052256031352291362">"പിൻ ചെയ്യുക"</string> + <string name="unpin_target" msgid="3556545602439143442">"അൺപിൻ ചെയ്യുക"</string> + <string name="app_info" msgid="6856026610594615344">"ആപ്പ് വിവരം"</string> </resources> diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml index b559e36ac92b..3321b5d2ce93 100644 --- a/core/res/res/values-mn-rMN/strings.xml +++ b/core/res/res/values-mn-rMN/strings.xml @@ -1031,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM карт нэмэгдсэн"</string> <string name="sim_added_message" msgid="7797975656153714319">"Үүрэн сүлжээнд хандах бол төхөөрөмжөө дахин асаан уу."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Дахин эхлүүлэх"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Цагийн тохируулах"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Огноо оруулах"</string> <string name="date_time_set" msgid="5777075614321087758">"Тохируулах"</string> @@ -1551,8 +1561,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Зарим функц байхгүй"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Үргэлжлүүлэхийн тулд дарах"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Хэрэглэгчийн профайл түгжээтэй"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>-д холбогдсон"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Файлыг үзэхийн тулд дарна уу"</string> + <string name="pin_target" msgid="3052256031352291362">"PIN"</string> + <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string> + <string name="app_info" msgid="6856026610594615344">"Апп-н мэдээлэл"</string> </resources> diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml index 5c4229b05549..3041601444c3 100644 --- a/core/res/res/values-mr-rIN/strings.xml +++ b/core/res/res/values-mr-rIN/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"सिम कार्ड जोडले"</string> <string name="sim_added_message" msgid="7797975656153714319">"सेल्युलर नेटवर्कवर प्रवेश करण्यासाठी आपले डिव्हाइस रीस्टार्ट करा."</string> <string name="sim_restart_button" msgid="4722407842815232347">"रीस्टार्ट"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"आपल्या नवीन सिमने योग्यरित्या कार्य करण्यासाठी, आपल्याला अॅप स्थापित करण्याची आणि तो आपल्या वाहकामधून उघडण्याची आवश्यकता असेल."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"अॅप मिळवा"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"आता नाही"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"नवीन सिम घाला"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"ते सेट करण्यासाठी टॅप करा"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"वेळ सेट करा"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"तारीख सेट करा"</string> <string name="date_time_set" msgid="5777075614321087758">"सेट करा"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"काही कार्ये कदाचित उपलब्ध नसू शकतात"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"सुरू ठेवण्यासाठी स्पर्श करा"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"वापरकर्ता प्रोफाईल लॉक केले"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> शी कनेक्ट केलेले"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"फायली पाहण्यासाठी टॅप करा"</string> + <string name="pin_target" msgid="3052256031352291362">"पिन"</string> + <string name="unpin_target" msgid="3556545602439143442">"अनपिन करा"</string> + <string name="app_info" msgid="6856026610594615344">"अॅप माहिती"</string> </resources> diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml index dca53aa889d8..d88d97f31097 100644 --- a/core/res/res/values-ms-rMY/strings.xml +++ b/core/res/res/values-ms-rMY/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"Tiada apl yang boleh menjalankan tindakan ini."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> telah berhenti"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> telah berhenti"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> asyik berhenti"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> asyik berhenti"</string> <string name="aerr_restart" msgid="9001379185665886595">"Mulakan semula apl"</string> <string name="aerr_reset" msgid="7645427603514220451">"Tetapkan semula dan mulakan semula apl"</string> <string name="aerr_report" msgid="5371800241488400617">"Hantar maklum balas"</string> <string name="aerr_close" msgid="2991640326563991340">"Tutup"</string> <string name="aerr_mute" msgid="7698966346654789433">"Redam"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Tunggu"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Tutup apl"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> tidak bertindak balas"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak bertindak balas"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> tidak bertindak balas"</string> + <string name="anr_process" msgid="6156880875555921105">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> tidak bertindak balas"</string> <string name="force_close" msgid="8346072094521265605">"OK"</string> <string name="report" msgid="4060218260984795706">"Laporkan"</string> <string name="wait" msgid="7147118217226317732">"Tunggu"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"Kad SIM ditambah"</string> <string name="sim_added_message" msgid="7797975656153714319">"Mulakan semula peranti anda untuk mengakses rangkaian selular."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Mulakan semula"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Tetapkan masa"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Tetapkan tarikh"</string> <string name="date_time_set" msgid="5777075614321087758">"Tetapkan"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Minta PIN sebelum menyahsemat"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Minta corak buka kunci sebelum menyahsemat"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Minta kata laluan sebelum menyahsemat"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Apl tidak boleh ditukar saiznya, tatal apl itu menggunakan dua jari."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Apl tidak menyokong skrin pisah."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Dipasang oleh pentadbir anda"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Dikemas kini oleh pentadbir anda"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Dipadamkan oleh pentadbir anda"</string> @@ -1561,10 +1561,11 @@ <string name="new_sms_notification_title" msgid="8442817549127555977">"Anda mempunyai mesej baharu"</string> <string name="new_sms_notification_content" msgid="7002938807812083463">"Buka apl SMS untuk melihat"</string> <string name="user_encrypted_title" msgid="7664361246988454307">"Sesetengah fungsi mgkn tidak tersedia"</string> - <string name="user_encrypted_message" msgid="7504541494700807850">"Sentuh untuk meneruskan"</string> + <string name="user_encrypted_message" msgid="7504541494700807850">"Ketik untuk meneruskan"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profil pengguna dikunci"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Disambungkan ke <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Ketik untuk melihat fail"</string> + <string name="pin_target" msgid="3052256031352291362">"Semat"</string> + <string name="unpin_target" msgid="3556545602439143442">"Nyahsemat"</string> + <string name="app_info" msgid="6856026610594615344">"Maklumat apl"</string> </resources> diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml index 34db25bee638..ca28662b453e 100644 --- a/core/res/res/values-my-rMM/strings.xml +++ b/core/res/res/values-my-rMM/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"ဆင်းမ်ကဒ် ထည့်ပါသည်"</string> <string name="sim_added_message" msgid="7797975656153714319">"ဆယ်လူလာ ကွန်ရက်ကို ရယူသုံးရန် သင့် ကိရိယာကို ပြန်ဖွင့်ပေးပါ။"</string> <string name="sim_restart_button" msgid="4722407842815232347">"အစက ပြန်စရန်"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"သင့် SIM အသစ်ပုံမှန် အလုပ်လုပ်ရန်၊ သင်အသုံးပြုသည့် မိုဘိုင်းဝန်ဆောင်မှုမှ အက်ပ်တစ်ခုထည့်သွင်း၍ ဖွင့်ရန်လိုအပ်ပါသည်။"</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"အက်ပ်ကို ရယူပါ"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"ယခုမဟုတ်သေးပါ"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"SIM အသစ်ထည့်သွင်းလိုက်ပါသည်"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"၎င်းကိုတပ်ဆင်ရန် တို့ပါ"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"အချိန်သတ်မှတ်ရန်"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"ရက်စွဲ အတည်ပြုရန်"</string> <string name="date_time_set" msgid="5777075614321087758">"အတည်ပြုရန်"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"အချို့လုပ်ဆောင်ချက်များ ရနိုင်သေးမည်မဟုတ်ပါ"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"ရှေ့ဆက်ရန်တို့ပါ"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"အသုံးပြုသူပရိုဖိုင် သော့ခတ်ထားသည်"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ချိတ်ဆက်ထားသည်"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ဖိုင်များကိုကြည့်ရန် တို့ပါ"</string> + <string name="pin_target" msgid="3052256031352291362">"တွဲပါ"</string> + <string name="unpin_target" msgid="3556545602439143442">"ဖြုတ်ပါ"</string> + <string name="app_info" msgid="6856026610594615344">"အက်ပ်အချက်အလက်"</string> </resources> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index ff292dbee28a..737743a59c46 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-kort er lagt til"</string> <string name="sim_added_message" msgid="7797975656153714319">"Start enheten på nytt for å få tilgang til mobilnettverket."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Start på nytt"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"For at det nye SIM-kortet ditt skal fungere skikkelig, må du installere og åpne en app fra operatøren din."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"SKAFF DEG APPEN"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"IKKE NÅ"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Et nytt SIM-kort er satt inn"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Trykk for å konfigurere"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Stille klokken"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Angi dato"</string> <string name="date_time_set" msgid="5777075614321087758">"Lagre"</string> @@ -1555,8 +1560,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Noen funksjoner kan være utilgjengelige"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Trykk for å fortsette"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Brukerprofilen er låst"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Koblet til <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Trykk for å se filer"</string> + <string name="pin_target" msgid="3052256031352291362">"Fest"</string> + <string name="unpin_target" msgid="3556545602439143442">"Løsne"</string> + <string name="app_info" msgid="6856026610594615344">"Info om appen"</string> </resources> diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml index 934337ca0696..7ea4b48b345d 100644 --- a/core/res/res/values-ne-rNP/strings.xml +++ b/core/res/res/values-ne-rNP/strings.xml @@ -1037,6 +1037,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM कार्ड थप गरियो"</string> <string name="sim_added_message" msgid="7797975656153714319">"सेलुलर सञ्जाल पहुँच गर्न तपाईँको उपकरण पुनः सुरु गर्नुहोस्।"</string> <string name="sim_restart_button" msgid="4722407842815232347">"पुनःस्टार्ट गर्नुहोस्"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"तपाईंको नयाँ SIM ले राम्रोसँग काम गर्न, तपाईंले आफ्नो वाहक मार्फत अनुप्रयोग स्थापना र खोल्न आवश्यक हुनेछ।"</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"अनुप्रयोग प्राप्त गर्नुहोस्"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"अहिले होइन"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"नयाँ SIM घुसाइयो"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"यसलाई सेटअप गर्न ट्याप गर्नुहोस्"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"समय मिलाउनुहोस्"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"मिति मिलाउनुहोस्"</string> <string name="date_time_set" msgid="5777075614321087758">"सेट गर्नुहोस्"</string> @@ -1541,7 +1546,7 @@ <string name="default_notification_topic_label" msgid="227586145791870829">"विविध"</string> <string name="importance_from_topic" msgid="3572280439880023233">"तपाईंले यी सूचनाहरूको महत्त्व सेट गर्नुहुन्छ।"</string> <string name="importance_from_person" msgid="9160133597262938296">"यसमा सङ्लग्न भएका मानिसहरूको कारणले गर्दा यो महत्वपूर्ण छ।"</string> - <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सँगै नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने ?"</string> + <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सँगै नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string> <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सँगै नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने (यस खाताको प्रयोगकर्ता पहिले नै अवस्थित छ) ?"</string> <string name="language_selection_title" msgid="7181332986330337171">"भाषाको प्राथमिकता"</string> <string name="country_selection_title" msgid="2954859441620215513">"क्षेत्रको प्राथमिकता"</string> @@ -1559,8 +1564,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"केही कार्यहरू उपलब्ध नहुन सक्छन्"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"जारी राख्नका लागि छुनुहोस्"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"प्रयोगकर्ता प्रोफाइल लक भयो"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> मा जडान गरिएको छ"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"फाइलहरू हेर्न ट्याप गर्नुहोस्"</string> + <string name="pin_target" msgid="3052256031352291362">"पिन गर्नुहोस्"</string> + <string name="unpin_target" msgid="3556545602439143442">"अनपिन गर्नुहोस्"</string> + <string name="app_info" msgid="6856026610594615344">"अनुप्रयोगका बारे जानकारी"</string> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index a5c1904cae86..750b7166559a 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Simkaart aangesloten"</string> <string name="sim_added_message" msgid="7797975656153714319">"Start je apparaat opnieuw voor toegang tot het mobiele netwerk."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Opnieuw starten"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Je moet een app van je provider installeren en openen om te zorgen dat je nieuwe simkaart correct werkt."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"DE APP DOWNLOADEN"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NIET NU"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Nieuwe simkaart geplaatst"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Tik om dit in te stellen"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Tijd instellen"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Datum instellen"</string> <string name="date_time_set" msgid="5777075614321087758">"Instellen"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Sommige functies zijn mogelijk niet beschikbaar"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Tik om door te gaan"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Gebruikersprofiel vergrendeld"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Verbonden met <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tik om bestanden te bekijken"</string> + <string name="pin_target" msgid="3052256031352291362">"Vastzetten"</string> + <string name="unpin_target" msgid="3556545602439143442">"Losmaken"</string> + <string name="app_info" msgid="6856026610594615344">"App-info"</string> </resources> diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml index 2f80f02fe8e1..05f0ce23fd74 100644 --- a/core/res/res/values-pa-rIN/strings.xml +++ b/core/res/res/values-pa-rIN/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM ਕਾਰਡ ਜੋੜਿਆ ਗਿਆ"</string> <string name="sim_added_message" msgid="7797975656153714319">"ਸੈਲਿਊਲਰ ਨੈਟਵਰਕ ਤੱਕ ਪਹੁੰਚ ਲਈ ਆਪਣੀ ਡਿਵਾਈਸ ਰੀਸਟਾਰਟ ਕਰੋ।"</string> <string name="sim_restart_button" msgid="4722407842815232347">"ਰੀਸਟਾਰਟ ਕਰੋ"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"ਤੁਹਾਡੀ ਨਵੀਂ SIM ਦੇ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਤੁਹਾਡੇ ਕੈਰੀਅਰ ਤੋਂ ਇੱਕ ਐਪ ਸਥਾਪਤ ਕਰਨ ਅਤੇ ਖੋਲ੍ਹਣ ਦੀ ਲੋੜ ਪਵੇਗੀ।"</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"ਐਪ ਪ੍ਰਾਪਤ ਕਰੋ"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"ਹੁਣੇ ਨਹੀਂ"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"ਨਵੀਂ SIM ਦਾਖਲ ਕੀਤੀ ਗਈ"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"ਇਸ ਨੂੰ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"ਸਮਾਂ ਸੈਟ ਕਰੋ"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"ਤਾਰੀਖ ਸੈਟ ਕਰੋ"</string> <string name="date_time_set" msgid="5777075614321087758">"ਸੈਟ ਕਰੋ"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"ਹੋ ਸਕਦਾ ਹੈ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਉਪਲਬਧ ਨਾ ਹੋਣ"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਸਪਰਸ਼ ਕਰੋ"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"ਵਰਤੋਂਕਾਰ ਪ੍ਰੋਫਾਈਲ ਲੌਕ ਕੀਤੀ ਗਈ"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋਈ"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ਫ਼ਾਈਲਾਂ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string> + <string name="pin_target" msgid="3052256031352291362">"ਪਿੰਨ ਕਰੋ"</string> + <string name="unpin_target" msgid="3556545602439143442">"ਅਨਪਿੰਨ ਕਰੋ"</string> + <string name="app_info" msgid="6856026610594615344">"ਐਪ ਜਾਣਕਾਰੀ"</string> </resources> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index e53ddb76f565..7e320a606be4 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1047,6 +1047,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Dodano kartę SIM"</string> <string name="sim_added_message" msgid="7797975656153714319">"Uruchom urządzenie ponownie, by uzyskać dostęp do sieci komórkowej."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Uruchom ponownie"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Aby nowa karta SIM działała prawidłowo, musisz zainstalować i otworzyć aplikację udostępnioną przez operatora."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"POBIERZ APLIKACJĘ"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NIE TERAZ"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Włożono nową kartę SIM"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Kliknij, by skonfigurować"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Ustaw godzinę"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Ustaw datę"</string> <string name="date_time_set" msgid="5777075614321087758">"Ustaw"</string> @@ -1591,8 +1596,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Niektóre funkcje mogą być niedostępne"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Kliknij, by kontynuować"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profil użytkownika zablokowany"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Połączono z: <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dotknij, by wyświetlić pliki"</string> + <string name="pin_target" msgid="3052256031352291362">"Przypnij"</string> + <string name="unpin_target" msgid="3556545602439143442">"Odepnij"</string> + <string name="app_info" msgid="6856026610594615344">"O aplikacji"</string> </resources> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index ce25b7d2be55..1e3a887cf6c9 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Cartão SIM adicionado"</string> <string name="sim_added_message" msgid="7797975656153714319">"Reinicie o dispositivo para acessar a rede celular."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Para que seu novo SIM funcione corretamente, instale e abra um app da sua operadora."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"FAZER O DOWNLOAD DO APP"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"AGORA NÃO"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Novo SIM inserido"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Toque para configurar"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Definir hora"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Definir data"</string> <string name="date_time_set" msgid="5777075614321087758">"Definir"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Algumas funções podem não estar disponíveis."</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Toque para continuar"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil do usuário bloqueado"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toque para ver os arquivos"</string> + <string name="pin_target" msgid="3052256031352291362">"Fixar guia"</string> + <string name="unpin_target" msgid="3556545602439143442">"Liberar guia"</string> + <string name="app_info" msgid="6856026610594615344">"Informações do app"</string> </resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 4ff5f3edb430..2855e9ba5ea1 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -232,7 +232,7 @@ <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string> - <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo oculto pela política"</string> + <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string> <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string> <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string> <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string> @@ -909,8 +909,8 @@ <string name="chooseActivity" msgid="7486876147751803333">"Escolha uma ação"</string> <string name="chooseUsbActivity" msgid="6894748416073583509">"Escolher uma aplicação para o dispositivo USB"</string> <string name="noApplications" msgid="2991814273936504689">"Nenhuma aplicação pode efetuar esta ação."</string> - <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> parou"</string> - <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> parou"</string> + <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> sofreu uma falha de sistema."</string> + <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> sofreu uma falha de sistema."</string> <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> continua a parar"</string> <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> continua a parar"</string> <string name="aerr_restart" msgid="9001379185665886595">"Reiniciar aplicação"</string> @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Cartão SIM adicionado"</string> <string name="sim_added_message" msgid="7797975656153714319">"Reinicie o dispositivo para aceder à rede móvel."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Para que o novo SIM funcione corretamente, tem de instalar e abrir uma aplicação do seu operador."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"OBTER A APLICAÇÃO"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"AGORA NÃO"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Novo SIM inserido"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Toque para configurar"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Definir hora"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Definir data"</string> <string name="date_time_set" msgid="5777075614321087758">"Definir"</string> @@ -1535,8 +1540,8 @@ <string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string> <string name="importance_from_topic" msgid="3572280439880023233">"Definiu a importância destas notificações."</string> <string name="importance_from_person" msgid="9160133597262938296">"É importante devido às pessoas envolvidas."</string> - <string name="user_creation_account_exists" msgid="1942606193570143289">"Permitir que o <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> - <string name="user_creation_adding" msgid="4482658054622099197">"Permitir que o <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string> + <string name="user_creation_account_exists" msgid="1942606193570143289">"Pretende permitir que o <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> + <string name="user_creation_adding" msgid="4482658054622099197">"Pretende permitir que o <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string> <string name="language_selection_title" msgid="7181332986330337171">"Preferência de idioma"</string> <string name="country_selection_title" msgid="2954859441620215513">"Preferência de região"</string> <string name="search_language_hint" msgid="7042102592055108574">"Intr. nome do idioma"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Algumas funções podem não estar disp."</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Toque para continuar"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil de utilizador bloqueado"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Ligado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Tocar para ver ficheiros"</string> + <string name="pin_target" msgid="3052256031352291362">"Fixar"</string> + <string name="unpin_target" msgid="3556545602439143442">"Soltar"</string> + <string name="app_info" msgid="6856026610594615344">"Informações da aplicação"</string> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index ce25b7d2be55..1e3a887cf6c9 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Cartão SIM adicionado"</string> <string name="sim_added_message" msgid="7797975656153714319">"Reinicie o dispositivo para acessar a rede celular."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Para que seu novo SIM funcione corretamente, instale e abra um app da sua operadora."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"FAZER O DOWNLOAD DO APP"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"AGORA NÃO"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Novo SIM inserido"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Toque para configurar"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Definir hora"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Definir data"</string> <string name="date_time_set" msgid="5777075614321087758">"Definir"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Algumas funções podem não estar disponíveis."</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Toque para continuar"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Perfil do usuário bloqueado"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectado a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toque para ver os arquivos"</string> + <string name="pin_target" msgid="3052256031352291362">"Fixar guia"</string> + <string name="unpin_target" msgid="3556545602439143442">"Liberar guia"</string> + <string name="app_info" msgid="6856026610594615344">"Informações do app"</string> </resources> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 8f659c93fab0..9ad5a5afcc03 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -49,7 +49,7 @@ <string name="serviceEnabled" msgid="8147278346414714315">"Serviciul a fost activat."</string> <string name="serviceEnabledFor" msgid="6856228140453471041">"Serviciul a fost activat pentru:"</string> <string name="serviceDisabled" msgid="1937553226592516411">"Serviciul a fost dezactivat."</string> - <string name="serviceRegistered" msgid="6275019082598102493">"Înregistrarea a reuşit."</string> + <string name="serviceRegistered" msgid="6275019082598102493">"Înregistrarea a reușit."</string> <string name="serviceErased" msgid="1288584695297200972">"Ștergerea a reușit."</string> <string name="passwordIncorrect" msgid="7612208839450128715">"Parolă incorectă."</string> <string name="mmiComplete" msgid="8232527495411698359">"MMI finalizat."</string> @@ -79,7 +79,7 @@ <string name="PinMmi" msgid="3113117780361190304">"Cod PIN modificat"</string> <string name="CnipMmi" msgid="3110534680557857162">"Se apelează numărul prezent"</string> <string name="CnirMmi" msgid="3062102121430548731">"Se apelează un număr restricţionat"</string> - <string name="ThreeWCMmi" msgid="9051047170321190368">"Apelare de tip conferinţă"</string> + <string name="ThreeWCMmi" msgid="9051047170321190368">"Apelare de tip conferință"</string> <string name="RuacMmi" msgid="7827887459138308886">"Respingere apeluri supărătoare nedorite"</string> <string name="CndMmi" msgid="3116446237081575808">"Se apelează serviciul de furnizare a numerelor"</string> <string name="DndMmi" msgid="1265478932418334331">"Nu deranjaţi"</string> @@ -88,7 +88,7 @@ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: Restricționat."</string> <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: nerestricționat"</string> <string name="serviceNotProvisioned" msgid="8614830180508686666">"Nu se asigură accesul la acest serviciu."</string> - <string name="CLIRPermanent" msgid="3377371145926835671">"Nu puteți să modificaţi setarea pentru ID-ul apelantului."</string> + <string name="CLIRPermanent" msgid="3377371145926835671">"Nu puteți să modificați setarea pentru ID-ul apelantului."</string> <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acces restricționat modificat"</string> <string name="RestrictedOnData" msgid="8653794784690065540">"Serviciul de date este blocat."</string> <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Serviciul de urgență este blocat."</string> @@ -138,8 +138,8 @@ <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecționată"</string> <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> după <xliff:g id="TIME_DELAY">{2}</xliff:g> (de) secunde"</string> - <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionat"</string> - <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionat"</string> + <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecționat"</string> + <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecționat"</string> <string name="fcComplete" msgid="3118848230966886575">"Cod de funcție complet."</string> <string name="fcError" msgid="3327560126588500777">"Problemă de conectare sau cod de funcție nevalid."</string> <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string> @@ -147,7 +147,7 @@ <string name="httpErrorLookup" msgid="4711687456111963163">"Nu s-a putut găsi adresa URL."</string> <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Schema de autentificare a site-ului nu este acceptată."</string> <string name="httpErrorAuth" msgid="1435065629438044534">"Nu s-a realizat autentificarea."</string> - <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Autentificarea prin intermediul serverului proxy nu a reuşit."</string> + <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Autentificarea prin intermediul serverului proxy nu a reușit."</string> <string name="httpErrorConnect" msgid="8714273236364640549">"Nu s-a putut stabili conexiunea cu serverul."</string> <string name="httpErrorIO" msgid="2340558197489302188">"Nu s-a putut efectua comunicarea cu serverul. Încercați din nou mai târziu."</string> <string name="httpErrorTimeout" msgid="4743403703762883954">"Conexiunea la server a expirat."</string> @@ -162,10 +162,10 @@ <string name="contentServiceSync" msgid="8353523060269335667">"Sincronizare"</string> <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizare"</string> <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Prea multe ştergeri <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string> - <string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeți câteva fișiere pentru a elibera spaţiu."</string> + <string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeți câteva fișiere pentru a elibera spațiu."</string> <string name="low_memory" product="watch" msgid="4415914910770005166">"Spațiul de stocare de pe ceas este plin! Ștergeți câteva fișiere pentru a elibera spațiu."</string> <string name="low_memory" product="tv" msgid="516619861191025923">"Spațiul de stocare al televizorului este plin. Ștergeți câteva fișiere pentru a elibera spațiu."</string> - <string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ștergeți câteva fișiere pentru a elibera spaţiu."</string> + <string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ștergeți câteva fișiere pentru a elibera spațiu."</string> <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rețeaua poate fi monitorizată"</string> <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"De o terță parte necunoscută"</string> <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"De administratorul profilului de serviciu"</string> @@ -199,7 +199,7 @@ <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"Televizorul se va închide."</string> <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ceasul dvs. se va închide."</string> <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonul dvs. se va închide."</string> - <string name="shutdown_confirm_question" msgid="2906544768881136183">"Doriți să închideţi?"</string> + <string name="shutdown_confirm_question" msgid="2906544768881136183">"Doriți să închideți?"</string> <string name="reboot_safemode_title" msgid="7054509914500140361">"Reporniţi în modul sigur"</string> <string name="reboot_safemode_confirm" msgid="55293944502784668">"Doriți să reporniţi în modul sigur? Astfel vor fi dezactivate toate aplicațiile terţă parte pe care le-ați instalat. Acestea vor fi restabilite când reporniţi din nou."</string> <string name="recent_tasks_title" msgid="3691764623638127888">"Recente"</string> @@ -290,7 +290,7 @@ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"citire feeduri abonat"</string> <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite aplicației să obţină detalii despre feedurile sincronizate în prezent."</string> <string name="permlab_sendSms" msgid="7544599214260982981">"trimită și să vadă mesajele SMS"</string> - <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariția unor taxe neaşteptate. Aplicaţiile rău intenţionate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string> + <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariția unor taxe neașteptate. Aplicaţiile rău intenţionate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string> <string name="permlab_readSms" msgid="8745086572213270480">"citeşte mesajele text (SMS sau MMS)"</string> <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite aplicației să citească mesajele SMS stocate pe tabletă sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conţinutul sau de gradul de confidenţialitate al acestora."</string> <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Permite aplicației să citească mesajele SMS stocate pe televizor sau pe cardul SIM. Cu această permisiune, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string> @@ -313,7 +313,7 @@ <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea tabletei."</string> <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea televizorului."</string> <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea telefonului."</string> - <string name="permlab_getPackageSize" msgid="7472921768357981986">"măsurare spaţiu de stocare al aplicației"</string> + <string name="permlab_getPackageSize" msgid="7472921768357981986">"măsurare spațiu de stocare al aplicației"</string> <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Permite aplicației să preia dimensiunile codului, ale datelor și ale memoriei cache"</string> <string name="permlab_writeSettings" msgid="2226195290955224730">"modifică setări de sistem"</string> <string name="permdesc_writeSettings" msgid="7775723441558907181">"Permite aplicației să modifice datele din setările sistemului. Aplicaţiile rău intenţionate pot corupe configuraţia sistemului dvs."</string> @@ -326,13 +326,13 @@ <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze televizorul, determinându-l să utilizeze prea multă memorie."</string> <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze telefonul, determinându-l să utilizeze prea multă memorie."</string> <string name="permlab_readContacts" msgid="8348481131899886131">"citeşte agenda"</string> - <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string> + <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string> <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Permite aplicației să citească datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string> - <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string> + <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string> <string name="permlab_writeContacts" msgid="5107492086416793544">"modifică agenda"</string> - <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string> + <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string> <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Permite aplicației să modifice datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane de contact. Cu această permisiune, aplicația poate șterge datele de contact."</string> - <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string> + <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string> <string name="permlab_readCallLog" msgid="3478133184624102739">"citeşte jurnalul de apeluri"</string> <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string> <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Permite aplicației să citească jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune, aplicațiile pot să salveze datele din jurnalul de apeluri, iar aplicațiile rău-intenționate pot permite accesul la datele din jurnalul de apeluri fără cunoștința dvs."</string> @@ -368,7 +368,7 @@ <string name="permlab_vibrate" msgid="7696427026057705834">"controlează vibrarea"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite aplicației să controleze mecanismul de vibrare."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"apelare directă numere de telefon"</string> - <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neaşteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string> + <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neașteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string> <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite aplicației să folosească serviciul IMS pentru apeluri, fără intervenția dvs."</string> <string name="permlab_readPhoneState" msgid="9178228524507610486">"citeşte starea și identitatea telefonului"</string> @@ -391,7 +391,7 @@ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Permite aplicației să schimbe fusul orar al tabletei."</string> <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Permite aplicației să modifice fusul orar al televizorului."</string> <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Permite aplicației să schimbe fusul orar al telefonului."</string> - <string name="permlab_getAccounts" msgid="1086795467760122114">"găseşte conturi pe dispozitiv"</string> + <string name="permlab_getAccounts" msgid="1086795467760122114">"găsește conturi pe dispozitiv"</string> <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Permite aplicației să obţină lista de conturi cunoscute de tabletă. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string> <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Permite aplicației să obțină lista de conturi cunoscute de televizor. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string> <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Permite aplicației să obţină lista de conturi cunoscute de telefon. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string> @@ -417,7 +417,7 @@ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite aplicației să configureze telefonul Bluetooth local, să descopere și să se împerecheze cu dispozitive la distanță."</string> <string name="permlab_accessWimaxState" msgid="4195907010610205703">"se conectează și se deconectează de la WiMAX"</string> <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permite aplicației să stabilească dacă o rețea WiMAX este activată și să vadă informațiile cu privire la toate reţelele WiMAX conectate."</string> - <string name="permlab_changeWimaxState" msgid="340465839241528618">"schimbaţi starea WiMAX"</string> + <string name="permlab_changeWimaxState" msgid="340465839241528618">"schimbați starea WiMAX"</string> <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite aplicației să conecteze și să deconecteze tableta la și de la reţelele WiMAX."</string> <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Permite aplicației să conecteze și să deconecteze televizorul la și de la rețelele WiMAX."</string> <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite aplicației să conecteze și să deconecteze telefonul la și de la reţelele WiMAX."</string> @@ -482,7 +482,7 @@ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Permite aplicației să citească utilizarea statistică a rețelei pentru anumite rețele și aplicații."</string> <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"gestionează politica de rețea"</string> <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite aplicației să gestioneze politicile de rețea și să definească regulile specifice aplicațiilor."</string> - <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificaţi modul de calcul al utilizării rețelei"</string> + <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificați modul de calcul al utilizării rețelei"</string> <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicației să modifice modul în care este calculată utilizarea rețelei pentru aplicații. Nu se utilizează de aplicațiile obişnuite."</string> <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string> <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string> @@ -663,12 +663,12 @@ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceţi parola pentru a debloca"</string> <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceţi codul PIN pentru a debloca"</string> <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Cod PIN incorect."</string> - <string name="keyguard_label_text" msgid="861796461028298424">"Pentru a debloca, apăsaţi Meniu, apoi 0."</string> + <string name="keyguard_label_text" msgid="861796461028298424">"Pentru a debloca, apăsați Meniu, apoi 0."</string> <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Număr de urgență"</string> <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Fără semnal"</string> <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ecranul este blocat."</string> <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Apăsați Meniu pentru a debloca sau pentru a efectua apeluri de urgență."</string> - <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Apăsaţi Meniu pentru deblocare."</string> + <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Apăsați Meniu pentru deblocare."</string> <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenaţi modelul pentru a debloca"</string> <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Urgență"</string> <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Reveniţi la apel"</string> @@ -700,9 +700,9 @@ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string> <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string> <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> (de) secunde."</string> - <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string> + <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați tableta cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string> <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați televizorul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string> - <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string> + <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați telefonul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string> <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Aţi efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string> <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a televizorului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, televizorul va reveni la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string> <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Aţi efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string> @@ -757,7 +757,7 @@ <string name="granularity_label_word" msgid="7075570328374918660">"cuvânt"</string> <string name="granularity_label_link" msgid="5815508880782488267">"link"</string> <string name="granularity_label_line" msgid="5764267235026120888">"rând"</string> - <string name="factorytest_failed" msgid="5410270329114212041">"Testarea de fabrică nu a reuşit"</string> + <string name="factorytest_failed" msgid="5410270329114212041">"Testarea de fabrică nu a reușit"</string> <string name="factorytest_not_system" msgid="4435201656767276723">"Acţiunea FACTORY_TEST este acceptată doar pentru pachetele instalate în /system/app."</string> <string name="factorytest_no_action" msgid="872991874799998561">"Nu s-a găsit niciun pachet care să ofere acțiunea FACTORY_TEST."</string> <string name="factorytest_reboot" msgid="6320168203050791643">"Reporniți"</string> @@ -799,7 +799,7 @@ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permite aplicației să adauge mesaje în Mesaje primite în mesageria vocală."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"modificare permisiuni pentru locația geografică a browserului"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permite aplicației să modifice permisiunile privind locația geografică a browserului. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a permite trimiterea informaţiilor privind locația către site-uri web arbitrare."</string> - <string name="save_password_message" msgid="767344687139195790">"Doriți ca browserul să reţină această parolă?"</string> + <string name="save_password_message" msgid="767344687139195790">"Doriți ca browserul să rețină această parolă?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Nu acum"</string> <string name="save_password_remember" msgid="6491879678996749466">"Reţineţi"</string> <string name="save_password_never" msgid="8274330296785855105">"Niciodată"</string> @@ -917,32 +917,24 @@ <string name="noApplications" msgid="2991814273936504689">"Această acţiune nu poate fi efectuată de nicio aplicație."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> s-a oprit"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> s-a oprit"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> se oprește încontinuu"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> se oprește încontinuu"</string> <string name="aerr_restart" msgid="9001379185665886595">"Reporniți aplicația"</string> <string name="aerr_reset" msgid="7645427603514220451">"Resetați și reporniți aplicația"</string> <string name="aerr_report" msgid="5371800241488400617">"Trimiteți feedback"</string> <string name="aerr_close" msgid="2991640326563991340">"Închideți"</string> <string name="aerr_mute" msgid="7698966346654789433">"Dezactivați"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Așteptați"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Închideți aplicația"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> nu răspunde"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nu răspunde"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> nu răspunde"</string> + <string name="anr_process" msgid="6156880875555921105">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> nu răspunde"</string> <string name="force_close" msgid="8346072094521265605">"OK"</string> - <string name="report" msgid="4060218260984795706">"Raportaţi"</string> + <string name="report" msgid="4060218260984795706">"Raportați"</string> <string name="wait" msgid="7147118217226317732">"Aşteptaţi"</string> - <string name="webpage_unresponsive" msgid="3272758351138122503">"Pagina a devenit inactivă.\n\nDoriți să o închideţi?"</string> + <string name="webpage_unresponsive" msgid="3272758351138122503">"Pagina a devenit inactivă.\n\nDoriți să o închideți?"</string> <string name="launch_warning_title" msgid="1547997780506713581">"Aplicaţie redirecţionată"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcţionează acum."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string> @@ -1037,7 +1029,7 @@ <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Acest lucru va genera costuri în contul dvs. mobil."</b></string> <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Trimiteți"</string> <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Anulați"</string> - <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Doresc să se reţină opțiunea"</string> + <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Doresc să se rețină opțiunea"</string> <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Puteți modifica ulterior în Setări > Aplicații"</string> <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Permiteți întotdeauna"</string> <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nu permiteți niciodată"</string> @@ -1047,6 +1039,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Card SIM adăugat"</string> <string name="sim_added_message" msgid="7797975656153714319">"Reporniți dispozitivul pentru a accesa rețeaua mobilă."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Reporniţi"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Pentru ca noul SIM să funcționeze corect, va trebui să instalați și să deschideți o aplicație de la operatorul dvs."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"DESCĂRCAȚI APLICAȚIA"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"NU ACUM"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"S-a introdus un card SIM nou"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Atingeți pentru a-l configura"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Setaţi ora"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Setaţi data"</string> <string name="date_time_set" msgid="5777075614321087758">"Setați"</string> @@ -1170,7 +1167,7 @@ <string name="next_button_label" msgid="1080555104677992408">"Înainte"</string> <string name="skip_button_label" msgid="1275362299471631819">"Omiteţi"</string> <string name="no_matches" msgid="8129421908915840737">"Nicio potrivire"</string> - <string name="find_on_page" msgid="1946799233822820384">"Găsiţi pe pagină"</string> + <string name="find_on_page" msgid="1946799233822820384">"Găsiți pe pagină"</string> <plurals name="matches_found" formatted="false" msgid="1210884353962081884"> <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> din <xliff:g id="TOTAL">%d</xliff:g></item> <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> din <xliff:g id="TOTAL">%d</xliff:g></item> @@ -1179,8 +1176,8 @@ <string name="action_mode_done" msgid="7217581640461922289">"Terminat"</string> <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Se șterge stocarea USB..."</string> <string name="progress_erasing" product="default" msgid="6596988875507043042">"Se șterge cardul SD..."</string> - <string name="share" msgid="1778686618230011964">"Distribuiţi"</string> - <string name="find" msgid="4808270900322985960">"Găsiţi"</string> + <string name="share" msgid="1778686618230011964">"Distribuiți"</string> + <string name="find" msgid="4808270900322985960">"Găsiți"</string> <string name="websearch" msgid="4337157977400211589">"Căutare pe web"</string> <string name="find_next" msgid="5742124618942193978">"Următorul rezultat"</string> <string name="find_previous" msgid="2196723669388360506">"Rezultatul anterior"</string> @@ -1190,7 +1187,7 @@ <string name="gpsVerifYes" msgid="2346566072867213563">"Da"</string> <string name="gpsVerifNo" msgid="1146564937346454865">"Nu"</string> <string name="sync_too_many_deletes" msgid="5296321850662746890">"Limita pentru ştergere a fost depăşită"</string> - <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> (de) elemente şterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce doriți să faceţi?"</string> + <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> (de) elemente şterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce doriți să faceți?"</string> <string name="sync_really_delete" msgid="2572600103122596243">"Ștergeți elementele"</string> <string name="sync_undo_deletes" msgid="2941317360600338602">"Anulați aceste ştergeri"</string> <string name="sync_do_nothing" msgid="3743764740430821845">"Nu trebuie să luați nicio măsură deocamdată"</string> @@ -1243,7 +1240,7 @@ <string name="storage_usb" msgid="3017954059538517278">"Dsipozitiv de stocare USB"</string> <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editați"</string> <string name="data_usage_warning_title" msgid="1955638862122232342">"Avertisment de utiliz. a datelor"</string> - <string name="data_usage_warning_body" msgid="2814673551471969954">"Atingeți pt. a afişa utiliz./set."</string> + <string name="data_usage_warning_body" msgid="2814673551471969954">"Atingeți pt. a afișa utiliz./set."</string> <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Ați atins limita de date 2G-3G"</string> <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Ați atins limita de date 4G"</string> <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Ați atins limita de date mobile"</string> @@ -1270,11 +1267,11 @@ <string name="fingerprints" msgid="4516019619850763049">"Amprente:"</string> <string name="sha256_fingerprint" msgid="4391271286477279263">"Amprentă SHA-256:"</string> <string name="sha1_fingerprint" msgid="7930330235269404581">"Amprentă SHA-1:"</string> - <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Afişaţi-le pe toate"</string> + <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Afișați-le pe toate"</string> <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Alegeți activitatea"</string> - <string name="share_action_provider_share_with" msgid="5247684435979149216">"Distribuiţi pentru"</string> + <string name="share_action_provider_share_with" msgid="5247684435979149216">"Distribuiți pentru"</string> <string name="sending" msgid="3245653681008218030">"Se trimite..."</string> - <string name="launchBrowserDefault" msgid="2057951947297614725">"Lansaţi browserul?"</string> + <string name="launchBrowserDefault" msgid="2057951947297614725">"Lansați browserul?"</string> <string name="SetupCallDefault" msgid="5834948469253758575">"Acceptați apelul?"</string> <string name="activity_resolver_use_always" msgid="8017770747801494933">"Întotdeauna"</string> <string name="activity_resolver_use_once" msgid="2404644797149173758">"Numai o dată"</string> @@ -1306,7 +1303,7 @@ <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", securizat"</string> <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Model uitat"</string> <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greşit"</string> - <string name="kg_wrong_password" msgid="2333281762128113157">"Parolă greşită"</string> + <string name="kg_wrong_password" msgid="2333281762128113157">"Parolă greșită"</string> <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greşit"</string> <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Încercați din nou peste <xliff:g id="NUMBER">%1$d</xliff:g> (de) secunde."</string> <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenaţi modelul"</string> @@ -1339,13 +1336,13 @@ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string> <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a televizorului. Televizorul va reveni acum la setările prestabilite din fabrică."</string> <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Telefonul va fi acum resetat la setările prestabilite din fabrică."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string> <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați televizorul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereuşite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> (de) secunde."</string> <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminaţi"</string> <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string> - <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Menţineţi două degete pe ecran pentru a activa accesibilitatea."</string> + <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mențineți două degete pe ecran pentru a activa accesibilitatea."</string> <string name="accessibility_enabled" msgid="1381972048564547685">"S-a activat accesibilitatea."</string> <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilitatea a fost anulată"</string> <string name="user_switched" msgid="3768006783166984410">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string> @@ -1480,10 +1477,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicită codul PIN înainte de a anula fixarea"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicită modelul pentru deblocare înainte de a anula fixarea"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicită parola înainte de a anula fixarea"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Aplicația nu poate fi redimensionată. Derulați în ea cu două degete."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplicația nu acceptă ecranul împărțit."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalat de administrator"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizat de un administrator"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Șters de administrator"</string> @@ -1582,8 +1577,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Este posibil ca unele funcții să nu fie disponibile"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Atingeți pentru a continua"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profil utilizator: blocat"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Conectat la <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Atingeți pentru a vedea fișierele"</string> + <string name="pin_target" msgid="3052256031352291362">"Fixați"</string> + <string name="unpin_target" msgid="3556545602439143442">"Anulați fixarea"</string> + <string name="app_info" msgid="6856026610594615344">"Informații despre aplicație"</string> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 5806ed8c8aa5..bdbeb545d20c 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1047,6 +1047,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-карта добавлена"</string> <string name="sim_added_message" msgid="7797975656153714319">"Перезагрузите устройство, чтобы подключиться к мобильной сети."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Перезапуск"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Настройка времени"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Настройка даты"</string> <string name="date_time_set" msgid="5777075614321087758">"Установить"</string> @@ -1591,8 +1601,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Некоторые функции недоступны"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Нажмите, чтобы продолжить"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Профиль заблокирован"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Подключено к <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Нажмите, чтобы просмотреть файлы"</string> + <string name="pin_target" msgid="3052256031352291362">"Закрепить"</string> + <string name="unpin_target" msgid="3556545602439143442">"Открепить"</string> + <string name="app_info" msgid="6856026610594615344">"О приложении"</string> </resources> diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml index 663fed832806..9bbab5609c5a 100644 --- a/core/res/res/values-si-rLK/strings.xml +++ b/core/res/res/values-si-rLK/strings.xml @@ -1033,6 +1033,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM පතක් එකතු කරන ලදි"</string> <string name="sim_added_message" msgid="7797975656153714319">"සෙලියුලර් ජාලයට ප්රවේශ වීමට ඔබගේ උපාංගය නැවත අරඹන්න."</string> <string name="sim_restart_button" msgid="4722407842815232347">"යළි අරඹන්න"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"ඔබේ නව SIM නිසි ලෙස වැඩ කිරීමට, ඔබ ඔබේ වාහකය වෙතින් යෙදුමක් ස්ථාපනය කර විවෘත කිරීම අවශ්යය."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"යෙදුම ලබා ගන්න"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"දැන්ම නොවේ"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"නව SIM ඇතුළු කරන්න"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"එය පිහිටුවීමට තට්ටු කරන්න"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"වේලාව සකසන්න"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"දිනය සැකසීම"</string> <string name="date_time_set" msgid="5777075614321087758">"සකසන්න"</string> @@ -1555,8 +1560,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"සමහර කාර්ය නොතිබිය හැකිය"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"දිගටම කරගෙන යාමට ස්පර්ශ කරන්න"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"පරිශීලක පැතිකඩ අගුලු දමා ඇත"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> වෙත සම්බන්ධ විය"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ගොනු බැලීමට තට්ටු කරන්න"</string> + <string name="pin_target" msgid="3052256031352291362">"අමුණන්න"</string> + <string name="unpin_target" msgid="3556545602439143442">"ගලවන්න"</string> + <string name="app_info" msgid="6856026610594615344">"යෙදුම් තොරතුරු"</string> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 850a959acffb..4369374fc85b 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1047,6 +1047,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Bola pridaná SIM karta"</string> <string name="sim_added_message" msgid="7797975656153714319">"Ak chcete získať prístup k mobilnej sieti, reštartujte svoje zariadenie."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Reštartovať"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Ak chcete, aby vaša nová SIM karta fungovala správne, musíte nainštalovať a spustiť aplikáciu od operátora."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"ZÍSKAŤ APLIKÁCIU"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"TERAZ NIE"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Bola vložená nová SIM karta"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Nastavte ju klepnutím"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Nastaviť čas"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Nastaviť dátum"</string> <string name="date_time_set" msgid="5777075614321087758">"Nastaviť"</string> @@ -1591,8 +1596,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Niektoré funkcie nemusia byť dostupné"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Pokračujte klepnutím"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profil používateľa je zamknutý"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Pripojené k zariadeniu <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Klepnutím zobrazíte súbory"</string> + <string name="pin_target" msgid="3052256031352291362">"Pripnúť"</string> + <string name="unpin_target" msgid="3556545602439143442">"Uvoľniť"</string> + <string name="app_info" msgid="6856026610594615344">"Info o aplikácii"</string> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 342dc4e04baf..00c47e78b828 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1047,6 +1047,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"Kartica SIM dodana"</string> <string name="sim_added_message" msgid="7797975656153714319">"Za dostop do mobilnega omrežja znova zaženite napravo."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Vnovičen zagon"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Nastavi uro"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Nastavi datum"</string> <string name="date_time_set" msgid="5777075614321087758">"Nastavi"</string> @@ -1591,8 +1601,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Nek. funk. morda niso na voljo"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Dotaknite se za nadaljevanje"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profil uporabnika zaklenjen"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Vzpostavljena povezava z napravo <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dotaknite se, če si želite ogledati datoteke"</string> + <string name="pin_target" msgid="3052256031352291362">"Pripenjanje"</string> + <string name="unpin_target" msgid="3556545602439143442">"Odpenjanje"</string> + <string name="app_info" msgid="6856026610594615344">"Podatki o aplikaciji"</string> </resources> diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml index 499ef155cb0e..70164bebd0ec 100644 --- a/core/res/res/values-sq-rAL/strings.xml +++ b/core/res/res/values-sq-rAL/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Karta SIM u shtua"</string> <string name="sim_added_message" msgid="7797975656153714319">"Rinise pajisjen për të pasur qasje në rrjetin celular."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Rifillo"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Që karta e re SIM të funksionojë siç duhet, duhet të instalosh dhe të hapësh një aplikacion nga operatori yt."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"MERR APLIKACIONIN"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"JO TANI"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Është futur kartë e re SIM"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Trokit për ta konfiguruar"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Cakto kohën"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Vendos datën"</string> <string name="date_time_set" msgid="5777075614321087758">"Cakto"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Disa funksione mund të mos jenë të disponueshme"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Preke për të vazhduar"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Profili i përdoruesit i kyçur"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"U lidh me <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Trokit për të parë skedarët"</string> + <string name="pin_target" msgid="3052256031352291362">"Gozhdo"</string> + <string name="unpin_target" msgid="3556545602439143442">"Zhgozhdo"</string> + <string name="app_info" msgid="6856026610594615344">"Informacioni mbi aplikacionin"</string> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 35139d1afe71..cb1712337471 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1039,6 +1039,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM картица је додата"</string> <string name="sim_added_message" msgid="7797975656153714319">"Поново покрените уређај да бисте приступили мобилној мрежи."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Поново покрени"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Подешавање времена"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Подешавање датума"</string> <string name="date_time_set" msgid="5777075614321087758">"Подеси"</string> @@ -1572,8 +1582,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Неке функције нису доступне"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Додирните да бисте наставили"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Профил корисника је закључан"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Повезано је са производом <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Додирните за преглед датотека"</string> + <string name="pin_target" msgid="3052256031352291362">"Закачи"</string> + <string name="unpin_target" msgid="3556545602439143442">"Откачи"</string> + <string name="app_info" msgid="6856026610594615344">"Информације о апликацији"</string> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 0eb3165d445c..f90f95c91261 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-kort lades till"</string> <string name="sim_added_message" msgid="7797975656153714319">"Starta om enheten om du vill få tillgång till mobilnätet."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Starta om"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Du måste installera och öppna en app från operatören om SIM-kortet ska fungera korrekt."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"HÄMTA APPEN"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"INTE NU"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Nytt SIM-kort har satts in"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Tryck om du vill konfigurera"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Ange tid"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Ange datum"</string> <string name="date_time_set" msgid="5777075614321087758">"Ställ in"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Vissa funktioner är inte tillgängliga"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Tryck om du vill fortsätta"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Användarprofilen är låst"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Ansluten till <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Filerna visas om du trycker här"</string> + <string name="pin_target" msgid="3052256031352291362">"Fäst"</string> + <string name="unpin_target" msgid="3556545602439143442">"Lossa"</string> + <string name="app_info" msgid="6856026610594615344">"Info om appen"</string> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index b1e35953b066..1c7f2e24acd4 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1033,6 +1033,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM kadi imeongezwa"</string> <string name="sim_added_message" msgid="7797975656153714319">"Zima na uwashe kifaa chako tena ili ufikie mitandao ya simu za mkononi."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Anza upya"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Weka muda"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Weka tarehe"</string> <string name="date_time_set" msgid="5777075614321087758">"Weka"</string> @@ -1555,8 +1565,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Huenda baadhi ya vipengele visipatikane"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Gusa ili uendelee"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Wasifu wa mtumiaji umefungwa"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Imeunganishwa na <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Gonga ili uangalie faili"</string> + <string name="pin_target" msgid="3052256031352291362">"Bandika"</string> + <string name="unpin_target" msgid="3556545602439143442">"Bandua"</string> + <string name="app_info" msgid="6856026610594615344">"Maelezo ya programu"</string> </resources> diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml index d1a00d97e3d5..8366985b591a 100644 --- a/core/res/res/values-ta-rIN/strings.xml +++ b/core/res/res/values-ta-rIN/strings.xml @@ -909,8 +909,8 @@ <string name="chooseActivity" msgid="7486876147751803333">"செயலைத் தேர்ந்தெடுக்கவும்"</string> <string name="chooseUsbActivity" msgid="6894748416073583509">"USB சாதனத்திற்கான பயன்பாட்டைத் தேர்வுசெய்க"</string> <string name="noApplications" msgid="2991814273936504689">"இந்தச் செயலைச் செய்ய பயன்பாடுகள் எதுவுமில்லை."</string> - <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> நிறுத்தப்பட்டது"</string> - <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> நிறுத்தப்பட்டது"</string> + <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> செயலிழந்தது"</string> + <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> செயலிழந்தது"</string> <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> தொடர்ந்து நிறுத்தப்படுகிறது"</string> <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> தொடர்ந்து நிறுத்தப்படுகிறது"</string> <string name="aerr_restart" msgid="9001379185665886595">"பயன்பாட்டை மீண்டும் தொடங்கு"</string> @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"சிம் கார்டு சேர்க்கப்பட்டது"</string> <string name="sim_added_message" msgid="7797975656153714319">"செல்லுலார் நெட்வொர்க்கை அணுக உங்கள் சாதனத்தை மறுதொடக்கம் செய்யவும்."</string> <string name="sim_restart_button" msgid="4722407842815232347">"மறுதொடக்கம்"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"புதிய சிம் சரியாக இயங்குவதற்கு, நீங்கள் பயன்படுத்தும் மொபைல் நிறுவனத்திலிருந்து பயன்பாட்டை நிறுவி, திறக்கவும்."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"பயன்பாட்டைப் பெறுக"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"இப்போது வேண்டாம்"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"புதிய சிம் செருகப்பட்டது"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"அமைக்க, தட்டவும்"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"நேரத்தை அமை"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"தேதியை அமை"</string> <string name="date_time_set" msgid="5777075614321087758">"அமை"</string> @@ -1544,7 +1549,7 @@ <string name="language_picker_section_all" msgid="3097279199511617537">"எல்லா மொழிகளும்"</string> <string name="locale_search_menu" msgid="2560710726687249178">"தேடு"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"பணிப் பயன்முறை முடக்கப்பட்டது"</string> - <string name="work_mode_off_message" msgid="3286169091278094476">"செயல்பட, பணி சுயவிவரத்தை அனுமதி. இதில் பயன்பாடுகள், பின்புல ஒத்திசைவு மற்றும் தொடர்புடைய அம்சங்கள் அடங்கும்."</string> + <string name="work_mode_off_message" msgid="3286169091278094476">"செயல்பட, பணி சுயவிவரத்தை அனுமதி. இதில் பயன்பாடுகள், பின்னணி ஒத்திசைவு மற்றும் தொடர்புடைய அம்சங்கள் அடங்கும்."</string> <string name="work_mode_turn_on" msgid="2062544985670564875">"இயக்கு"</string> <string name="suspended_package_title" msgid="3408150347778524435">"%1$s முடக்கப்பட்டது"</string> <string name="suspended_package_message" msgid="6341091587106868601">"%1$s நிர்வாகி முடக்கியுள்ளார். மேலும் அறிய, அவரைத் தொடர்புகொள்ளவும்."</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"சில செயல்பாடு கிடைக்காமல் போகலாம்"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"தொடர, தொடவும்"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"பயனர் சுயவிவரம் பூட்டப்பட்டது"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> உடன் இணைக்கப்பட்டது"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"கோப்புகளைப் பார்க்க, தட்டவும்"</string> + <string name="pin_target" msgid="3052256031352291362">"பின் செய்"</string> + <string name="unpin_target" msgid="3556545602439143442">"பின்னை அகற்று"</string> + <string name="app_info" msgid="6856026610594615344">"பயன்பாட்டுத் தகவல்"</string> </resources> diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml index d26794af05fb..6d42955553d5 100644 --- a/core/res/res/values-te-rIN/strings.xml +++ b/core/res/res/values-te-rIN/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"సిమ్ కార్డు జోడించబడింది"</string> <string name="sim_added_message" msgid="7797975656153714319">"సెల్యులార్ నెట్వర్క్ను ప్రాప్యత చేయడానికి మీ పరికరాన్ని పునఃప్రారంభించండి."</string> <string name="sim_restart_button" msgid="4722407842815232347">"పునఃప్రారంభించు"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"మీ SIM సక్రమంగా పని చేస్తుండటానికి, మీరు మీ క్యారియర్ నుండి ఒక అనువర్తనాన్ని ఇన్స్టాల్ చేసుకొని, తెరవాలి."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"అనువర్తనాన్ని పొందండి"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"ఇప్పుడు కాదు"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"కొత్త SIM చొప్పించారు"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"దీన్ని సెటప్ చేయడానికి నొక్కండి"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"సమయాన్ని సెట్ చేయండి"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"తేదీని సెట్ చేయండి"</string> <string name="date_time_set" msgid="5777075614321087758">"సెట్ చేయి"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"కొన్ని విధులు ఉండకపోవచ్చు"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"కొనసాగడానికి తాకండి"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"వినియోగ. ప్రొఫైల్ లాక్ అయింది"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ఫైల్లను వీక్షించడానికి నొక్కండి"</string> + <string name="pin_target" msgid="3052256031352291362">"పిన్ చేయి"</string> + <string name="unpin_target" msgid="3556545602439143442">"అన్పిన్ చేయి"</string> + <string name="app_info" msgid="6856026610594615344">"అనువర్తన సమాచారం"</string> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 04e04bb027e0..6aa3b8ab6719 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"ไม่มีแอปพลิเคชันใดทำงานนี้ได้"</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> หยุดทำงาน"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> หยุดทำงาน"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> หยุดทำงานอยู่เรื่อยๆ"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> หยุดทำงานอยู่เรื่อยๆ"</string> <string name="aerr_restart" msgid="9001379185665886595">"เปิดแอปใหม่"</string> <string name="aerr_reset" msgid="7645427603514220451">"รีเซ็ตแอปและเปิดใหม่"</string> <string name="aerr_report" msgid="5371800241488400617">"ส่งความคิดเห็น"</string> <string name="aerr_close" msgid="2991640326563991340">"ปิด"</string> <string name="aerr_mute" msgid="7698966346654789433">"ปิด"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"รอ"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"ปิดแอป"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> ไม่ตอบสนอง"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ไม่ตอบสนอง"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> ไม่ตอบสนอง"</string> + <string name="anr_process" msgid="6156880875555921105">"กระบวนการ <xliff:g id="PROCESS">%1$s</xliff:g> ไม่ตอบสนอง"</string> <string name="force_close" msgid="8346072094521265605">"ตกลง"</string> <string name="report" msgid="4060218260984795706">"รายงาน"</string> <string name="wait" msgid="7147118217226317732">"รอ"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"เพิ่มซิมการ์ดแล้ว"</string> <string name="sim_added_message" msgid="7797975656153714319">"รีสตาร์ทอุปกรณ์เพื่อเข้าถึงเครือข่ายมือถือ"</string> <string name="sim_restart_button" msgid="4722407842815232347">"รีสตาร์ท"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"ตั้งเวลา"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"ตั้งวันที่"</string> <string name="date_time_set" msgid="5777075614321087758">"ตั้งค่า"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ขอ PIN ก่อนเลิกตรึง"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ขอรูปแบบการปลดล็อกก่อนเลิกตรึง"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ขอรหัสผ่านก่อนเลิกตรึง"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"แอปไม่สามารถปรับขนาดได้ เลื่อนแอปด้วยนิ้ว 2 นิ้ว"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"แอปไม่สนับสนุนการแยกหน้าจอ"</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"ติดตั้งโดยผู้ดูแลระบบของคุณ"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"อัปเดตโดยผู้ดูแลระบบ"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"ลบโดยผู้ดูแลระบบของคุณ"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"บางฟังก์ชันอาจไม่พร้อมใช้งาน"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"แตะเพื่อดำเนินการต่อ"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"โปรไฟล์ผู้ใช้ถูกล็อก"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"เชื่อมต่อ <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> แล้ว"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"แตะเพื่อดูไฟล์"</string> + <string name="pin_target" msgid="3052256031352291362">"ปักหมุด"</string> + <string name="unpin_target" msgid="3556545602439143442">"เลิกปักหมุด"</string> + <string name="app_info" msgid="6856026610594615344">"ข้อมูลแอป"</string> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index bf06b97126e5..9be3b2b79471 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"Walang apps ang makakapagsagawa ng pagkilos na ito."</string> <string name="aerr_application" msgid="250320989337856518">"Huminto ang <xliff:g id="APPLICATION">%1$s</xliff:g>"</string> <string name="aerr_process" msgid="6201597323218674729">"Huminto ang <xliff:g id="PROCESS">%1$s</xliff:g>"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"Paulit-ulit na humihinto ang <xliff:g id="APPLICATION">%1$s</xliff:g>"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"Paulit-ulit na humihinto ang <xliff:g id="PROCESS">%1$s</xliff:g>"</string> <string name="aerr_restart" msgid="9001379185665886595">"I-restart ang app"</string> <string name="aerr_reset" msgid="7645427603514220451">"I-reset at i-restart ang app"</string> <string name="aerr_report" msgid="5371800241488400617">"Magpadala ng feedback"</string> <string name="aerr_close" msgid="2991640326563991340">"Isara"</string> <string name="aerr_mute" msgid="7698966346654789433">"I-mute"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Maghintay"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Isara ang app"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"Hindi tumutugon ang <xliff:g id="APPLICATION">%2$s</xliff:g>"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"Hindi tumutugon ang <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string> + <string name="anr_application_process" msgid="6417199034861140083">"Hindi tumutugon ang <xliff:g id="APPLICATION">%1$s</xliff:g>"</string> + <string name="anr_process" msgid="6156880875555921105">"Hindi tumutugon ang prosesong <xliff:g id="PROCESS">%1$s</xliff:g>"</string> <string name="force_close" msgid="8346072094521265605">"OK"</string> <string name="report" msgid="4060218260984795706">"Ulat"</string> <string name="wait" msgid="7147118217226317732">"Maghintay"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"Idinagdag ang SIM card"</string> <string name="sim_added_message" msgid="7797975656153714319">"I-restart ang iyong device upang ma-access ang cellular network."</string> <string name="sim_restart_button" msgid="4722407842815232347">"I-restart"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Magtakda ng oras"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Itakda ang petsa"</string> <string name="date_time_set" msgid="5777075614321087758">"Itakda"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Humingi ng PIN bago mag-unpin"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Humingi ng pattern sa pag-unlock bago mag-unpin"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Humingi ng password bago mag-unpin"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Hindi nare-resize ang app, mag-scroll dito gamit ang dalawang daliri."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Hindi sinusuportahan ng app ang split-screen."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Na-install ng iyong administrator"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Na-update ng iyong administrator"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Na-delete ng iyong administrator"</string> @@ -1567,4 +1567,7 @@ <skip /> <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> <skip /> + <string name="pin_target" msgid="3052256031352291362">"I-pin"</string> + <string name="unpin_target" msgid="3556545602439143442">"I-unpin"</string> + <string name="app_info" msgid="6856026610594615344">"Impormasyon ng app"</string> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index afef03eba50b..60e1b89768ec 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"Bu eylemi hiçbir uygulama gerçekleştiremez."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> durdu"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> durdu"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> sürekli olarak duruyor"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> sürekli olarak duruyor"</string> <string name="aerr_restart" msgid="9001379185665886595">"Uygulamayı yeniden başlat"</string> <string name="aerr_reset" msgid="7645427603514220451">"Uygulamayı sıfırla ve yeniden başlat"</string> <string name="aerr_report" msgid="5371800241488400617">"Geri bildirim gönder"</string> <string name="aerr_close" msgid="2991640326563991340">"Kapat"</string> <string name="aerr_mute" msgid="7698966346654789433">"Yok say"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Bekle"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Uygulamayı kapat"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> yanıt vermiyor"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> yanıt vermiyor"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> yanıt vermiyor"</string> + <string name="anr_process" msgid="6156880875555921105">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi yanıt vermiyor"</string> <string name="force_close" msgid="8346072094521265605">"Tamam"</string> <string name="report" msgid="4060218260984795706">"Bildir"</string> <string name="wait" msgid="7147118217226317732">"Bekle"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM kart eklendi"</string> <string name="sim_added_message" msgid="7797975656153714319">"Hücresel ağa erişmek için cihazınızı yeniden başlatın."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Yeniden başlat"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Saati ayarlayın"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Tarihi ayarlayın"</string> <string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Sabitlemeyi kaldırmadan önce PIN\'i sor"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Sabitlemeyi kaldırmadan önce kilit açma desenini sor"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Sabitlemeyi kaldırmadan önce şifre sor"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Uygulama yeniden boyutlandırılamaz. İki parmağınızla kaydırın."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Uygulama bölünmüş ekranı desteklemiyor."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Yöneticiniz tarafından yüklendi"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Yöneticiniz tarafından güncellendi"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Yöneticiniz tarafından silindi"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Bazı işlevler kullanılamayabilir"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Devam etmek için dokunun"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Kullanıcı profili kilitli"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> cihazına bağlandı"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Dosyaları görüntülemek için hafifçe dokunun"</string> + <string name="pin_target" msgid="3052256031352291362">"Sabitle"</string> + <string name="unpin_target" msgid="3556545602439143442">"Sabitlemeyi kaldır"</string> + <string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 888a083d9243..3eb3fd837ee6 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1047,6 +1047,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM-карту додано"</string> <string name="sim_added_message" msgid="7797975656153714319">"Щоб з’єднатися з мобільною мережею, перезавантажте пристрій."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Перезапуск"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Щоб ваша нова SIM-карта працювала правильно, установіть і відкрийте додаток від оператора."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"ЗАВАНТАЖИТИ ДОДАТОК"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"НЕ ЗАРАЗ"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Вставлено нову SIM-карту"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Торкніться, щоб налаштувати"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Установити час"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Установити дату"</string> <string name="date_time_set" msgid="5777075614321087758">"Застосувати"</string> @@ -1591,8 +1596,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Деякі функції можуть бути недоступні"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Торкніться, щоб продовжити"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Профіль користувача блокується"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Під’єднано до пристрою <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Торкніться, щоб переглянути файли"</string> + <string name="pin_target" msgid="3052256031352291362">"Закріпити"</string> + <string name="unpin_target" msgid="3556545602439143442">"Відкріпити"</string> + <string name="app_info" msgid="6856026610594615344">"Про додаток"</string> </resources> diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml index 3b316862b4b4..7b32a3cf46b5 100644 --- a/core/res/res/values-ur-rPK/strings.xml +++ b/core/res/res/values-ur-rPK/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"کوئی ایپس یہ کارروائی نہیں کر سکتی ہیں۔"</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> بند ہو گئی ہے"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> بند ہو گیا ہے"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> بار بار بند ہوتی ہے"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> بار بار بند ہوتی ہے"</string> <string name="aerr_restart" msgid="9001379185665886595">"ایپ دوبارہ شروع کریں"</string> <string name="aerr_reset" msgid="7645427603514220451">"ایپ کو دوبارہ ترتیب دیں اور دوبارہ شروع کریں"</string> <string name="aerr_report" msgid="5371800241488400617">"تاثرات بھیجیں"</string> <string name="aerr_close" msgid="2991640326563991340">"بند کریں"</string> <string name="aerr_mute" msgid="7698966346654789433">"خاموش کریں"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"انتظار کریں"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"ایپ بند کریں"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> جواب نہیں دے رہی ہے"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> جواب نہیں دے رہی ہے"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> جواب نہیں دے رہی ہے"</string> + <string name="anr_process" msgid="6156880875555921105">"کارروائی <xliff:g id="PROCESS">%1$s</xliff:g> جواب نہیں دے رہی ہے"</string> <string name="force_close" msgid="8346072094521265605">"ٹھیک ہے"</string> <string name="report" msgid="4060218260984795706">"اطلاع دیں"</string> <string name="wait" msgid="7147118217226317732">"انتظار کریں"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM شامل کیا گیا"</string> <string name="sim_added_message" msgid="7797975656153714319">"سیلولر نیٹ ورک تک رسائی کیلئے اپنا آلہ دوبارہ سٹارٹ کریں۔"</string> <string name="sim_restart_button" msgid="4722407842815232347">"دوبارہ شروع کریں"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"وقت سیٹ کریں"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"تاریخ سیٹ کریں"</string> <string name="date_time_set" msgid="5777075614321087758">"سیٹ کریں"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"پن ہٹانے سے پہلے PIN طلب کریں"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"پن ہٹانے سے پہلے غیر مقفل کرنے کا پیٹرن طلب کریں"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"پن ہٹانے سے پہلے پاس ورڈ طلب کریں"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"ایپ ری سائز ایبل نہیں ہے، اسے دو انگلیوں کے ساتھ سکرول کریں۔"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"آپ کے منتظم کی جانب سے انسٹال کر دیا گیا"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"آپ کے منتظم نے اپ ڈيٹ کر دیا"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"آپ کے منتظم کی جانب سے حذف کر دیا گیا"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"ممکن ہے کچھ فنکشز دستیاب نہ ہوں"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"جاری رکھنے کیلئے تھپتھپائیں"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"صارف پروفائل مقفل ہو گئی"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> سے منسلک"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"فائلوں کو دیکھنے کیلئے تھپتھپائیں"</string> + <string name="pin_target" msgid="3052256031352291362">"پن کریں"</string> + <string name="unpin_target" msgid="3556545602439143442">"پن ہٹائیں"</string> + <string name="app_info" msgid="6856026610594615344">"ایپ کی معلومات"</string> </resources> diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml index c944c0cd0744..d69df0422f39 100644 --- a/core/res/res/values-uz-rUZ/strings.xml +++ b/core/res/res/values-uz-rUZ/strings.xml @@ -313,7 +313,7 @@ <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Ilovaga o‘zining komponentlarini xotirada doimiy saqlashga ruxsat beradi. Bu mavjud xotirani cheklashi va telefonni sekin ishlashiga sabab bo‘lishi mumkin."</string> <string name="permlab_getPackageSize" msgid="7472921768357981986">"ilovalar egallagan xotira joyini hisoblash"</string> <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Ilova o‘zining kodi, ma’lumotlari va kesh o‘lchami to‘g‘risidagi ma’lumotlarni olishi mumkin"</string> - <string name="permlab_writeSettings" msgid="2226195290955224730">"tizim moslamalarini o‘zgartirish"</string> + <string name="permlab_writeSettings" msgid="2226195290955224730">"tizim sozlamalarini o‘zgartirish"</string> <string name="permdesc_writeSettings" msgid="7775723441558907181">"Ilova tizim sozlamalarini o‘zgartirishi mumkin. Zararli dasturlar uning yordamida tizimni ishdan chiqarishi mumkin."</string> <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"tizim ishga tushganda bajarish"</string> <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Ilova tizim qayta yoqilganidan so‘ng o‘zini ishga tushirishi mumkin. Bu planshetning yonish vaqtini uzaytirishi va doimiy ishlab turivchi ilova tufayli uning tezkor ishlashini kamaytirishi mumkin."</string> @@ -351,7 +351,7 @@ <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Ilovaga telefoningizda o‘zgartirishingiz mumkin bo‘lgan, shuningdek, do‘stlaringiz va hamkasblaringizning tadbirlarini qo‘shish, o‘chirish va o‘zgartirish uchun ruxsat beradi. Bu ilovaga go‘yoki taqvim egalari nomidan kelgan xabarlarni jo‘natishga yoki egasiga bildirmasdan tadbirlarni o‘zgartirishga ruxsat berishi mumkin."</string> <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"qo‘shimcha manzillarga kirish buyruqlari"</string> <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Ilovaga qo‘shimcha joylashuv xizmati buyruqlaridan foydalanishga ruxsat beradi. Uning yordamida ilova GPS yoki boshqa joylashuv ma’lumoti manbalarining ishlashiga xalaqit qilishi mumkin."</string> - <string name="permlab_accessFineLocation" msgid="251034415460950944">"aniq joylashuv (GPS va tarmoqqa asoslanib) ma’lumotlaridan foydalanishga ruxsat"</string> + <string name="permlab_accessFineLocation" msgid="251034415460950944">"aniq joylashuv ma’lumotiga kirish (GPS va tarmoq asosida)"</string> <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Ilovaga global joylashuvni aniqlash tizimi (GPS) yoki Wi-Fi va uyali tarmoq antennalari kabi tarmoq joylashuv manbalaridan foydalanib, aniq joylashuvingizni topishga ruxsat beradi. Ushbu joylashuv xizmatlari yoqib qo‘yilgan bo‘lishi va qurilmangizdagi ilovaga ulardan foydalanish uchun mavjud bo‘lishi kerak. Ilovalar bundan foydalanib, sizning joylashuvingizni aniqlaydi. Bu batareya quvvatini ko‘proq sarflaydi."</string> <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"taxminiy joylashuv (tarmoq asosida) ma’lumotlaridan foydalanishga ruxsat"</string> <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Ilovaga sizning taxminiy joylashuvingizni topishga ruxsat beradi. Ushbu joylashuv Wi-Fi va uyali tarmoq antennalari kabi tarmoq joylashuv manbalaridan foydlanuvchi joylashuv xizmatlari orqali aniqlanadi. Ushbu joylashuv xizmatlari yoqib qo‘yilgan bo‘lishi va qurilmangizdagi ilovaga ulardan foydalanish uchun mavjud bo‘lishi kerak. Ilovalar bundan foydalanib, sizning taxminiy joylashuvingizni aniqlaydi."</string> @@ -389,7 +389,7 @@ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Iloba planshetdagi vaqt zonasini o‘zgartirishi mumkin."</string> <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Ilovaga televizorning vaqt zonasini o‘zgartirish huquqini beradi."</string> <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Ilova telefondagi vaqt zonasini o‘zgartirishi mumkin."</string> - <string name="permlab_getAccounts" msgid="1086795467760122114">"qurilmadagi hisoblarni topish"</string> + <string name="permlab_getAccounts" msgid="1086795467760122114">"qurilmadagi hisoblarni qidirish"</string> <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Ilovaga planshetdagi hisoblar ro‘yxatini olishga ruxsat beradi. Bunga siz o‘rnatgan ilovalar tomonidan yaratilgan har qanday hisoblar kirishi mumkin."</string> <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Ilovaga televizor tomonidan aniqlangan hisoblar ro‘yxatini olish huquqini beradi. Bunga siz o‘rnatgan ilovalar tomonidan yaratilgan har qanday hisoblar kiradi."</string> <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Ilovaga telefondagi hisoblar ro‘yxatini olishga ruxsat beradi. Bunga siz o‘rnatgan ilovalar tomonidan yaratilgan har qanday hisoblar kirishi mumkin."</string> @@ -454,7 +454,7 @@ <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Ilovaga hisobning sinxronlash sozlamalarini o‘zgartirish uchun ruxsat beradi. Masalan, bundan \"Odamlar\" ilovasini hisob bilan sinxronlanlash uchun foydalanish mumkin."</string> <string name="permlab_readSyncStats" msgid="7396577451360202448">"sinxronlash statistikasini o‘qish"</string> <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Ilovaga hisobning sinxronlash statistikasini, shu jumladan, sinxronlangan hodisalar tarixi va qancha ma’lumot sinxronlanganligi haqidagi ma’lumotni o‘qishga ruxsat beradi."</string> - <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"USB xotirasi tarkibidagilarni o‘qish"</string> + <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"USB xotiradagi ma’lumotlarni ko‘rish"</string> <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"SD xotira kartasi tarkibidagilarni o‘qish"</string> <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Dasturga USB xotiradagi ma’lumotlarini ko‘rib chiqish uchun ruxsat beradi."</string> <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Dasturga SD kartadagi ma’lumotlarni ko‘rib chiqishga ruxsat berish."</string> @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"Hech qaysi ilova ushbu amalni bajara olmaydi."</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishdan chiqdi"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> jarayoni ishdan chiqdi"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> yana ishdan chiqdi"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> yana ishdan chiqdi"</string> <string name="aerr_restart" msgid="9001379185665886595">"Ilovani qayta ishga tushirish"</string> <string name="aerr_reset" msgid="7645427603514220451">"Ilovani qayta tiklash va qayta ishga tushirish"</string> <string name="aerr_report" msgid="5371800241488400617">"Fikr-mulohaza yuborish"</string> <string name="aerr_close" msgid="2991640326563991340">"Yopish"</string> <string name="aerr_mute" msgid="7698966346654789433">"E’tiborsiz qoldirish"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"Kuting"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"Ilovani yopish"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g> javob bermayapti"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g> javob bermayapti"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g> javob bermayapti"</string> + <string name="anr_process" msgid="6156880875555921105">"<xliff:g id="PROCESS">%1$s</xliff:g> ilovasi javob bermayapti"</string> <string name="force_close" msgid="8346072094521265605">"OK"</string> <string name="report" msgid="4060218260984795706">"Xabar berish"</string> <string name="wait" msgid="7147118217226317732">"Kuting"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM karta qo‘shildi"</string> <string name="sim_added_message" msgid="7797975656153714319">"Mobil tarmoqqa ulanish uchun qurilmangizni o‘chirib yoqing."</string> <string name="sim_restart_button" msgid="4722407842815232347">"O‘chirib-yoqish"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Vaqtni o‘rnatish"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Sanani kiritish"</string> <string name="date_time_set" msgid="5777075614321087758">"O‘rnatish"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Yechishda PIN-kod so‘ralsin"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Bo‘shatishdan oldin chizmali parol so‘ralsin"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Bo‘shatishdan oldin parol so‘ralsin"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"Oyna o‘lchamini o‘zgartirib bo‘lmaydi. Sahifani ikkita barmoq bilan aylantiring."</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Bu ilova ekranni bo‘lish xususiyatini qo‘llab-quvvatlamaydi."</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"Administratoringiz tomonidan o‘rnatilgan"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"Administratoringiz tomonidan yangilandi"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratoringiz tomonidan o‘chirilgan"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Ayrim funksiyalar mavjud bo‘lmasligi mumkin"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Davom etish uchun bosing"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Foydalanuvchi profili yopiq"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> mahsulotiga ulandi"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Fayllarni ko‘rish uchun bosing"</string> + <string name="pin_target" msgid="3052256031352291362">"Qadash"</string> + <string name="unpin_target" msgid="3556545602439143442">"Olib tashlash"</string> + <string name="app_info" msgid="6856026610594615344">"Ilova haqida"</string> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 6dc6017699ee..bbfef63199f4 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1031,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"Đã thêm thẻ SIM"</string> <string name="sim_added_message" msgid="7797975656153714319">"Khởi động lại thiết bị của bạn để truy cập mạng di động."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Khởi động lại"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Đặt giờ"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Đặt ngày"</string> <string name="date_time_set" msgid="5777075614321087758">"Đặt"</string> @@ -1557,4 +1567,7 @@ <skip /> <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> <skip /> + <string name="pin_target" msgid="3052256031352291362">"Ghim"</string> + <string name="unpin_target" msgid="3556545602439143442">"Bỏ ghim"</string> + <string name="app_info" msgid="6856026610594615344">"Thông tin ứng dụng"</string> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 12bd179f506c..938571ed92a5 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -232,8 +232,7 @@ <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g> 条)"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"内容已隐藏"</string> - <!-- no translation found for notification_hidden_by_policy_text (9004631276932584600) --> - <skip /> + <string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"内容已隐藏(根据政策规定)"</string> <string name="safeMode" msgid="2788228061547930246">"安全模式"</string> <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string> <string name="user_owner_label" msgid="2804351898001038951">"个人"</string> @@ -912,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"没有应用可执行此操作。"</string> <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g>已停止运行"</string> <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g>已停止运行"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g>屡次停止运行"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g>屡次停止运行"</string> <string name="aerr_restart" msgid="9001379185665886595">"重启应用"</string> <string name="aerr_reset" msgid="7645427603514220451">"重置并重启应用"</string> <string name="aerr_report" msgid="5371800241488400617">"发送反馈"</string> <string name="aerr_close" msgid="2991640326563991340">"关闭"</string> <string name="aerr_mute" msgid="7698966346654789433">"忽略"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"等待"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"关闭应用"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"<xliff:g id="APPLICATION">%2$s</xliff:g>没有响应"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"<xliff:g id="ACTIVITY">%1$s</xliff:g>没有响应"</string> + <string name="anr_application_process" msgid="6417199034861140083">"<xliff:g id="APPLICATION">%1$s</xliff:g>没有响应"</string> + <string name="anr_process" msgid="6156880875555921105">"进程“<xliff:g id="PROCESS">%1$s</xliff:g>”没有响应"</string> <string name="force_close" msgid="8346072094521265605">"确定"</string> <string name="report" msgid="4060218260984795706">"报告"</string> <string name="wait" msgid="7147118217226317732">"等待"</string> @@ -1040,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"已添加SIM卡"</string> <string name="sim_added_message" msgid="7797975656153714319">"请重新启动您的设备,以便使用移动网络。"</string> <string name="sim_restart_button" msgid="4722407842815232347">"重新启动"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"设置时间"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"设置日期"</string> <string name="date_time_set" msgid="5777075614321087758">"设置"</string> @@ -1471,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消时要求输入PIN码"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消时要求绘制解锁图案"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消时要求输入密码"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"无法调整该应用的大小,请用双指滚动该应用。"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"应用不支持分屏。"</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理员安装"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"由您单位的管理员更新"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"已被管理员删除"</string> @@ -1546,10 +1545,8 @@ <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string> <string name="importance_from_topic" msgid="3572280439880023233">"这些通知的重要性由您来设置。"</string> <string name="importance_from_person" msgid="9160133597262938296">"这条通知涉及特定的人,因此被归为重要通知。"</string> - <!-- no translation found for user_creation_account_exists (1942606193570143289) --> - <skip /> - <!-- no translation found for user_creation_adding (4482658054622099197) --> - <skip /> + <string name="user_creation_account_exists" msgid="1942606193570143289">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 创建新用户吗?"</string> + <string name="user_creation_adding" msgid="4482658054622099197">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g>(目前已有用户使用此帐号)创建新用户吗?"</string> <string name="language_selection_title" msgid="7181332986330337171">"语言偏好设置"</string> <string name="country_selection_title" msgid="2954859441620215513">"区域偏好设置"</string> <string name="search_language_hint" msgid="7042102592055108574">"输入语言名称"</string> @@ -1563,14 +1560,14 @@ <string name="suspended_package_message" msgid="6341091587106868601">"该软件包已被%1$s管理员禁用。请与管理员联系以了解详情。"</string> <string name="new_sms_notification_title" msgid="8442817549127555977">"您有新消息"</string> <string name="new_sms_notification_content" msgid="7002938807812083463">"打开短信应用查看"</string> - <!-- no translation found for user_encrypted_title (7664361246988454307) --> - <skip /> - <!-- no translation found for user_encrypted_message (7504541494700807850) --> - <skip /> - <!-- no translation found for user_encrypted_detail (979981584766912935) --> - <skip /> + <string name="user_encrypted_title" msgid="7664361246988454307">"部分功能可能无法使用"</string> + <string name="user_encrypted_message" msgid="7504541494700807850">"触摸即可继续"</string> + <string name="user_encrypted_detail" msgid="979981584766912935">"用户个人资料已锁定"</string> <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> <skip /> <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> <skip /> + <string name="pin_target" msgid="3052256031352291362">"固定"</string> + <string name="unpin_target" msgid="3556545602439143442">"取消固定"</string> + <string name="app_info" msgid="6856026610594615344">"应用信息"</string> </resources> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index efa55f11f7e8..620458ca3c64 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"沒有應用程式可執行這項操作。"</string> <string name="aerr_application" msgid="250320989337856518">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」已經停止運作"</string> <string name="aerr_process" msgid="6201597323218674729">"「<xliff:g id="PROCESS">%1$s</xliff:g>」已經停止運作"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」不斷停止運作"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"「<xliff:g id="PROCESS">%1$s</xliff:g>」不斷停止運作"</string> <string name="aerr_restart" msgid="9001379185665886595">"重新啟動應用程式"</string> <string name="aerr_reset" msgid="7645427603514220451">"重設並重新啟動應用程式"</string> <string name="aerr_report" msgid="5371800241488400617">"傳送意見反映"</string> <string name="aerr_close" msgid="2991640326563991340">"關閉"</string> <string name="aerr_mute" msgid="7698966346654789433">"忽略"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"等一下"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"關閉應用程式"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"「<xliff:g id="APPLICATION">%2$s</xliff:g>」沒有回應"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"「<xliff:g id="ACTIVITY">%1$s</xliff:g>」沒有回應"</string> + <string name="anr_application_process" msgid="6417199034861140083">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」沒有回應"</string> + <string name="anr_process" msgid="6156880875555921105">"處理程序「<xliff:g id="PROCESS">%1$s</xliff:g>」沒有回應"</string> <string name="force_close" msgid="8346072094521265605">"確定"</string> <string name="report" msgid="4060218260984795706">"報告"</string> <string name="wait" msgid="7147118217226317732">"等待"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM 卡已新增"</string> <string name="sim_added_message" msgid="7797975656153714319">"重新啟動裝置,才能使用流動網絡。"</string> <string name="sim_restart_button" msgid="4722407842815232347">"重新啟動"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"設定時間"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"日期設定"</string> <string name="date_time_set" msgid="5777075614321087758">"設定"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消固定時必須畫出解鎖圖案"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消固定時必須輸入密碼"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"無法調整應用程式的大小,請用兩隻手指捲動此應用程式。"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"應用程式不支援分割畫面。"</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理員安裝"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"已由您的管理員更新"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"已由管理員刪除"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"部分功能可能無法使用"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"輕觸即可繼續"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"使用者個人檔案目前處於鎖定狀態"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"已連線至 <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"輕按即可查看檔案"</string> + <string name="pin_target" msgid="3052256031352291362">"固定"</string> + <string name="unpin_target" msgid="3556545602439143442">"取消固定"</string> + <string name="app_info" msgid="6856026610594615344">"應用程式資料"</string> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 5f968fd58528..f56bc14c1cf7 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -911,28 +911,20 @@ <string name="noApplications" msgid="2991814273936504689">"沒有應用程式可執行這項操作。"</string> <string name="aerr_application" msgid="250320989337856518">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」已停止運作"</string> <string name="aerr_process" msgid="6201597323218674729">"「<xliff:g id="PROCESS">%1$s</xliff:g>」已停止運作"</string> - <!-- no translation found for aerr_application_repeated (3146328699537439573) --> - <skip /> - <!-- no translation found for aerr_process_repeated (6235302956890402259) --> - <skip /> + <string name="aerr_application_repeated" msgid="3146328699537439573">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」屢次停止運作"</string> + <string name="aerr_process_repeated" msgid="6235302956890402259">"「<xliff:g id="PROCESS">%1$s</xliff:g>」屢次停止運作"</string> <string name="aerr_restart" msgid="9001379185665886595">"重新啟動應用程式"</string> <string name="aerr_reset" msgid="7645427603514220451">"重設並重新啟動應用程式"</string> <string name="aerr_report" msgid="5371800241488400617">"提供意見"</string> <string name="aerr_close" msgid="2991640326563991340">"關閉"</string> <string name="aerr_mute" msgid="7698966346654789433">"忽略"</string> - <!-- no translation found for aerr_wait (3199956902437040261) --> - <skip /> - <!-- no translation found for aerr_close_app (3269334853724920302) --> - <skip /> + <string name="aerr_wait" msgid="3199956902437040261">"等一下"</string> + <string name="aerr_close_app" msgid="3269334853724920302">"關閉應用程式"</string> <string name="anr_title" msgid="4351948481459135709"></string> - <!-- no translation found for anr_activity_application (8493290105678066167) --> - <skip /> - <!-- no translation found for anr_activity_process (1622382268908620314) --> - <skip /> - <!-- no translation found for anr_application_process (6417199034861140083) --> - <skip /> - <!-- no translation found for anr_process (6156880875555921105) --> - <skip /> + <string name="anr_activity_application" msgid="8493290105678066167">"「<xliff:g id="APPLICATION">%2$s</xliff:g>」沒有回應"</string> + <string name="anr_activity_process" msgid="1622382268908620314">"「<xliff:g id="ACTIVITY">%1$s</xliff:g>」沒有回應"</string> + <string name="anr_application_process" msgid="6417199034861140083">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」沒有回應"</string> + <string name="anr_process" msgid="6156880875555921105">"「<xliff:g id="PROCESS">%1$s</xliff:g>」程序沒有回應"</string> <string name="force_close" msgid="8346072094521265605">"確定"</string> <string name="report" msgid="4060218260984795706">"回報"</string> <string name="wait" msgid="7147118217226317732">"等待"</string> @@ -1039,6 +1031,16 @@ <string name="sim_added_title" msgid="3719670512889674693">"SIM 卡已新增"</string> <string name="sim_added_message" msgid="7797975656153714319">"請重新啟動裝置,才能使用行動網路。"</string> <string name="sim_restart_button" msgid="4722407842815232347">"重新啟動"</string> + <!-- no translation found for carrier_app_dialog_message (7066156088266319533) --> + <skip /> + <!-- no translation found for carrier_app_dialog_button (7900235513678617329) --> + <skip /> + <!-- no translation found for carrier_app_dialog_not_now (6361378684292268027) --> + <skip /> + <!-- no translation found for carrier_app_notification_title (8921767385872554621) --> + <skip /> + <!-- no translation found for carrier_app_notification_text (1132487343346050225) --> + <skip /> <string name="time_picker_dialog_title" msgid="8349362623068819295">"設定時間"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"日期設定"</string> <string name="date_time_set" msgid="5777075614321087758">"設定"</string> @@ -1470,10 +1472,8 @@ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string> <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消固定時必須畫出解鎖圖案"</string> <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消固定時必須輸入密碼"</string> - <!-- no translation found for dock_cropped_windows_text (6378424064779004428) --> - <skip /> - <!-- no translation found for dock_non_resizeble_failed_to_dock_text (3871617304250207291) --> - <skip /> + <string name="dock_cropped_windows_text" msgid="6378424064779004428">"無法調整這個應用程式的大小,請用雙指捲動該應用程式。"</string> + <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"這個應用程式不支援分割畫面。"</string> <string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理員安裝"</string> <string name="package_updated_device_owner" msgid="8856631322440187071">"由您的管理員更新"</string> <string name="package_deleted_device_owner" msgid="7650577387493101353">"已遭管理員刪除"</string> @@ -1563,8 +1563,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"部分功能可能無法使用"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"輕觸即可繼續作業"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"使用者個人資料目前處於鎖定狀態"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"已連線至 <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"輕按即可查看檔案"</string> + <string name="pin_target" msgid="3052256031352291362">"固定"</string> + <string name="unpin_target" msgid="3556545602439143442">"取消固定"</string> + <string name="app_info" msgid="6856026610594615344">"應用程式資訊"</string> </resources> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 217249ef6c83..9fd47254f5de 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1031,6 +1031,11 @@ <string name="sim_added_title" msgid="3719670512889674693">"Ikhadi le-SIM lengeziwe"</string> <string name="sim_added_message" msgid="7797975656153714319">"Qala kabusha idivayisi yakho ukuze ufinyelele inethiwekhi yeselula."</string> <string name="sim_restart_button" msgid="4722407842815232347">"Qala phansi"</string> + <string name="carrier_app_dialog_message" msgid="7066156088266319533">"Ukuze wenze i-SIM yakho entsha isebenze kahle, kuzomele ufake uphinde uvule uhlelo lokusebenza kusukela kunkampani yakho yenethiwekhi."</string> + <string name="carrier_app_dialog_button" msgid="7900235513678617329">"THOLA UHLELO LOKUSEBENZA"</string> + <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"HHAYI MANJE"</string> + <string name="carrier_app_notification_title" msgid="8921767385872554621">"Kufakwe i-SIM entsha"</string> + <string name="carrier_app_notification_text" msgid="1132487343346050225">"Thepha ukuze uyisethe"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"Hlela isikhathi"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"Setha idethi"</string> <string name="date_time_set" msgid="5777075614321087758">"Hlela"</string> @@ -1553,8 +1558,9 @@ <string name="user_encrypted_title" msgid="7664361246988454307">"Eminye imisebenzi ingahle ingatholakali"</string> <string name="user_encrypted_message" msgid="7504541494700807850">"Thinta ukuze uqhubeke"</string> <string name="user_encrypted_detail" msgid="979981584766912935">"Iphrofayela yomsebenzisi ikhiyiwe"</string> - <!-- no translation found for usb_mtp_launch_notification_title (8359219638312208932) --> - <skip /> - <!-- no translation found for usb_mtp_launch_notification_description (8541876176425411358) --> - <skip /> + <string name="usb_mtp_launch_notification_title" msgid="8359219638312208932">"Kuxhumekile ku-<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> + <string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Thepha ukuze ubuke onke amafayela"</string> + <string name="pin_target" msgid="3052256031352291362">"Phina"</string> + <string name="unpin_target" msgid="3556545602439143442">"Susa ukuphina"</string> + <string name="app_info" msgid="6856026610594615344">"Ulwazi lohlelo lokusebenza"</string> </resources> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 15a4ad853535..3a5336cd05f1 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -429,10 +429,7 @@ sets. --> <attr name="multiArch" format ="boolean" /> - <!-- Specify abiOverride for multiArch application. - @hide - @SystemApi - --> + <!-- Specify abiOverride for multiArch application. --> <attr name="abiOverride" /> <!-- Specify whether a component is allowed to have multiple instances diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 7c6f3389c5d0..8e86f78e02fd 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -449,5 +449,7 @@ <item type="dimen" format="integer" name="time_picker_column_start_material">0</item> <item type="dimen" format="integer" name="time_picker_column_end_material">1</item> + <item type="dimen" name="aerr_padding_list_top">15dp</item> + <item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 329e2e55b0f8..5c5aff0998fa 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2697,6 +2697,9 @@ <public type="attr" name="endY" /> <public type="attr" name="offset" /> <public type="attr" name="abiOverride" /> + <public type="attr" name="bitmap" /> + <public type="attr" name="hotSpotX" /> + <public type="attr" name="hotSpotY" /> <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 e5a6226fd937..4e10d39e0005 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4176,7 +4176,7 @@ <string name="language_selection_title">Language preference</string> <!-- Title for the region selection screen [CHAR LIMIT=25] --> <string name="country_selection_title">Region preference</string> - <!-- Hint text in a search edit box (used to filter long language / country lists) [CHAR LIMIT=20] --> + <!-- Hint text in a search edit box (used to filter long language / country lists) [CHAR LIMIT=25] --> <string name="search_language_hint">Type language name</string> <!-- List section subheader for the language picker, containing a list of suggested languages determined by the default region [CHAR LIMIT=30] --> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index f0960c78d418..86b9f1d1b7d5 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1403,8 +1403,12 @@ please see styles_device_defaults.xml. <item name="textAppearance">?attr/textAppearanceListItemSmall</item> <item name="textColor">?attr/textColorAlertDialogListItem</item> <item name="gravity">center_vertical</item> - <item name="paddingStart">?attr/listPreferredItemPaddingStart</item> - <item name="paddingEnd">?attr/listPreferredItemPaddingEnd</item> + <item name="paddingStart">?attr/dialogPreferredPadding</item> + <item name="paddingEnd">?attr/dialogPreferredPadding</item> + <item name="background">?attr/selectableItemBackground</item> + <item name="drawablePadding">32dp</item> + <item name="drawableTint">@color/accent_material_light</item> + <item name="drawableTintMode">src_atop</item> </style> <!-- Wifi dialog styles --> diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java index 19ce44a90815..3feb0e905f1a 100644 --- a/core/tests/coretests/src/android/print/BasePrintTest.java +++ b/core/tests/coretests/src/android/print/BasePrintTest.java @@ -141,7 +141,7 @@ public abstract class BasePrintTest extends InstrumentationTestCase { // Set to US locale. Resources resources = getInstrumentation().getTargetContext().getResources(); Configuration oldConfiguration = resources.getConfiguration(); - if (!oldConfiguration.getLocales().getPrimary().equals(Locale.US)) { + if (!oldConfiguration.getLocales().get(0).equals(Locale.US)) { mOldLocale = oldConfiguration.getLocales(); DisplayMetrics displayMetrics = resources.getDisplayMetrics(); Configuration newConfiguration = new Configuration(oldConfiguration); diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk index d2bd10613ded..de741b376d16 100644 --- a/data/fonts/Android.mk +++ b/data/fonts/Android.mk @@ -89,10 +89,7 @@ $(eval include $(BUILD_PREBUILT)) endef font_src_files := \ - Clockopia.ttf \ - AndroidClock.ttf \ - AndroidClock_Highlight.ttf \ - AndroidClock_Solid.ttf + AndroidClock.ttf $(foreach f, $(font_src_files), $(call build-one-font-module, $(f))) diff --git a/data/fonts/AndroidClock_Highlight.ttf b/data/fonts/AndroidClock_Highlight.ttf Binary files differdeleted file mode 100644 index 923bb30a2328..000000000000 --- a/data/fonts/AndroidClock_Highlight.ttf +++ /dev/null diff --git a/data/fonts/AndroidClock_Solid.ttf b/data/fonts/AndroidClock_Solid.ttf Binary files differdeleted file mode 100644 index 923bb30a2328..000000000000 --- a/data/fonts/AndroidClock_Solid.ttf +++ /dev/null diff --git a/data/fonts/Clockopia.ttf b/data/fonts/Clockopia.ttf Binary files differdeleted file mode 100644 index 3f7b6aaa8c08..000000000000 --- a/data/fonts/Clockopia.ttf +++ /dev/null diff --git a/data/fonts/MTLc3m.ttf b/data/fonts/MTLc3m.ttf Binary files differdeleted file mode 100644 index e9018f62825e..000000000000 --- a/data/fonts/MTLc3m.ttf +++ /dev/null diff --git a/data/fonts/MTLmr3m.ttf b/data/fonts/MTLmr3m.ttf Binary files differdeleted file mode 100644 index 14f27d4f1847..000000000000 --- a/data/fonts/MTLmr3m.ttf +++ /dev/null diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk index 597a12245c11..acd785ede249 100644 --- a/data/fonts/fonts.mk +++ b/data/fonts/fonts.mk @@ -20,7 +20,4 @@ PRODUCT_COPY_FILES := \ PRODUCT_PACKAGES := \ DroidSansFallback.ttf \ DroidSansMono.ttf \ - Clockopia.ttf \ AndroidClock.ttf \ - AndroidClock_Highlight.ttf \ - AndroidClock_Solid.ttf \ diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index 961d0ebec7e4..dc302c719af7 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -344,6 +344,9 @@ <family lang="und-Zsye"> <font weight="400" style="normal">NotoColorEmoji.ttf</font> </family> + <family> + <font weight="400" style="normal">DroidSansFallback.ttf</font> + </family> <!-- Tai Le and Mongolian are intentionally kept last, to make sure they don't override the East Asian punctuation for Chinese. diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index dfb8bb86f1e5..534121a2e361 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -459,7 +459,7 @@ public class Paint { // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV // ? HINTING_OFF : HINTING_ON); mCompatScaling = mInvCompatScaling = 1; - setTextLocales(LocaleList.getDefault()); + setTextLocales(LocaleList.getAdjustedDefault()); } /** @@ -500,7 +500,7 @@ public class Paint { mInvCompatScaling = 1; mBidiFlags = BIDI_DEFAULT_LTR; - setTextLocales(LocaleList.getDefault()); + setTextLocales(LocaleList.getAdjustedDefault()); setElegantTextHeight(false); mFontFeatureSettings = null; } @@ -1292,7 +1292,7 @@ public class Paint { */ @NonNull public Locale getTextLocale() { - return mLocales.getPrimary(); + return mLocales.get(0); } /** @@ -1317,7 +1317,7 @@ public class Paint { if (locale == null) { throw new IllegalArgumentException("locale cannot be null"); } - if (mLocales != null && mLocales.size() == 1 && locale.equals(mLocales.getPrimary())) { + if (mLocales != null && mLocales.size() == 1 && locale.equals(mLocales.get(0))) { return; } mLocales = new LocaleList(locale); @@ -1340,8 +1340,8 @@ public class Paint { * each language. * * By default, the text locale list is initialized to a one-member list just containing the - * system locale (as returned by {@link LocaleList#getDefault()}). This assumes that the text to - * be rendered will most likely be in the user's preferred language. + * system locales. This assumes that the text to be rendered will most likely be in the user's + * preferred language. * * If the actual language or languages of the text is/are known, then they can be provided to * the text renderer using this method. The text renderer may attempt to guess the diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java index 40dbe2770e01..0cde0b990456 100644 --- a/graphics/java/android/graphics/Rect.java +++ b/graphics/java/android/graphics/Rect.java @@ -335,6 +335,21 @@ public final class Rect implements Parcelable { } /** + * Insets the rectangle on all sides specified by the insets. + * @hide + * @param left The amount to add from the rectangle's left + * @param top The amount to add from the rectangle's top + * @param right The amount to subtract from the rectangle's right + * @param bottom The amount to subtract from the rectangle's bottom + */ + public void inset(int left, int top, int right, int bottom) { + this.left += left; + this.top += top; + this.right -= right; + this.bottom -= bottom; + } + + /** * Returns true if (x,y) is inside the rectangle. The left and top are * considered to be inside, while the right and bottom are not. This means * that for a x,y to be contained: left <= x < right and top <= y < bottom. diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 0a3e27e94c06..c48c371ebdfd 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -19,10 +19,6 @@ import android.animation.AnimatorInflater; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.Animator.AnimatorListener; -import android.animation.PropertyValuesHolder; -import android.animation.TimeInterpolator; -import android.animation.ValueAnimator; -import android.animation.ObjectAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.ColorStateList; @@ -38,23 +34,14 @@ import android.graphics.Rect; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.Log; -import android.util.LongArray; -import android.util.PathParser; -import android.util.TimeUtils; -import android.view.Choreographer; -import android.view.DisplayListCanvas; -import android.view.RenderNode; -import android.view.RenderNodeAnimatorSetHelper; import android.view.View; import com.android.internal.R; -import com.android.internal.util.VirtualRefBasePtr; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; -import java.lang.ref.WeakReference; import java.util.ArrayList; /** @@ -151,7 +138,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false; /** Local, mutable animator set. */ - private final VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimator(); + private final AnimatorSet mAnimatorSet = new AnimatorSet(); /** * The resources against which this drawable was created. Used to attempt @@ -213,9 +200,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { @Override public void draw(Canvas canvas) { - if (canvas.isHardwareAccelerated()) { - mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas); - } mAnimatedVectorState.mVectorDrawable.draw(canvas); if (isStarted()) { invalidateSelf(); @@ -598,8 +582,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { * Resets the AnimatedVectorDrawable to the start state as specified in the animators. */ public void reset() { - mAnimatorSet.reset(); - invalidateSelf(); + // TODO: Use reverse or seek to implement reset, when AnimatorSet supports them. + start(); + mAnimatorSet.cancel(); } @Override @@ -618,12 +603,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { @NonNull private void ensureAnimatorSet() { if (!mHasAnimatorSet) { - // TODO: Skip the AnimatorSet creation and init the VectorDrawableAnimator directly - // with a list of LocalAnimators. - AnimatorSet set = new AnimatorSet(); - mAnimatedVectorState.prepareLocalAnimators(set, mRes); + mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mRes); mHasAnimatorSet = true; - mAnimatorSet.initWithAnimatorSet(set); mRes = null; } } @@ -713,13 +694,13 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } }; } - mAnimatorSet.setListener(mAnimatorListener); + mAnimatorSet.addListener(mAnimatorListener); } // A helper function to clean up the animator listener in the mAnimatorSet. private void removeAnimatorSetListener() { if (mAnimatorListener != null) { - mAnimatorSet.removeListener(); + mAnimatorSet.removeListener(mAnimatorListener); mAnimatorListener = null; } } @@ -748,407 +729,4 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mAnimationCallbacks.clear(); } - - /** - * @hide - */ - public static class VectorDrawableAnimator { - private AnimatorListener mListener = null; - private final LongArray mStartDelays = new LongArray(); - private PropertyValuesHolder.PropertyValues mTmpValues = - new PropertyValuesHolder.PropertyValues(); - private long mSetPtr = 0; - private boolean mContainsSequentialAnimators = false; - private boolean mStarted = false; - private boolean mInitialized = false; - private boolean mAnimationPending = false; - private boolean mIsReversible = false; - // TODO: Consider using NativeAllocationRegistery to track native allocation - private final VirtualRefBasePtr mSetRefBasePtr; - private WeakReference<RenderNode> mTarget = null; - private WeakReference<RenderNode> mLastSeenTarget = null; - - - VectorDrawableAnimator() { - mSetPtr = nCreateAnimatorSet(); - // Increment ref count on native AnimatorSet, so it doesn't get released before Java - // side is done using it. - mSetRefBasePtr = new VirtualRefBasePtr(mSetPtr); - } - - private void initWithAnimatorSet(AnimatorSet set) { - if (mInitialized) { - // Already initialized - throw new UnsupportedOperationException("VectorDrawableAnimator cannot be " + - "re-initialized"); - } - parseAnimatorSet(set, 0); - mInitialized = true; - - // Check reversible. - if (mContainsSequentialAnimators) { - mIsReversible = false; - } else { - // Check if there's any start delay set on child - for (int i = 0; i < mStartDelays.size(); i++) { - if (mStartDelays.get(i) > 0) { - mIsReversible = false; - return; - } - } - } - mIsReversible = true; - } - - private void parseAnimatorSet(AnimatorSet set, long startTime) { - ArrayList<Animator> animators = set.getChildAnimations(); - - boolean playTogether = set.shouldPlayTogether(); - // Convert AnimatorSet to VectorDrawableAnimator - for (int i = 0; i < animators.size(); i++) { - Animator animator = animators.get(i); - // Here we only support ObjectAnimator - if (animator instanceof AnimatorSet) { - parseAnimatorSet((AnimatorSet) animator, startTime); - } else if (animator instanceof ObjectAnimator) { - createRTAnimator((ObjectAnimator) animator, startTime); - } // ignore ValueAnimators and others because they don't directly modify VD - // therefore will be useless to AVD. - - if (!playTogether) { - // Assume not play together means play sequentially - startTime += animator.getTotalDuration(); - mContainsSequentialAnimators = true; - } - } - } - - // TODO: This method reads animation data from already parsed Animators. We need to move - // this step further up the chain in the parser to avoid the detour. - private void createRTAnimator(ObjectAnimator animator, long startTime) { - PropertyValuesHolder[] values = animator.getValues(); - Object target = animator.getTarget(); - if (target instanceof VectorDrawable.VGroup) { - createRTAnimatorForGroup(values, animator, (VectorDrawable.VGroup) target, - startTime); - } else if (target instanceof VectorDrawable.VPath) { - for (int i = 0; i < values.length; i++) { - values[i].getPropertyValues(mTmpValues); - if (mTmpValues.endValue instanceof PathParser.PathData && - mTmpValues.propertyName.equals("pathData")) { - createRTAnimatorForPath(animator, (VectorDrawable.VPath) target, - startTime); - } else if (target instanceof VectorDrawable.VFullPath) { - createRTAnimatorForFullPath(animator, (VectorDrawable.VFullPath) target, - startTime); - } else { - throw new IllegalArgumentException("ClipPath only supports PathData " + - "property"); - } - - } - } else if (target instanceof VectorDrawable.VectorDrawableState) { - createRTAnimatorForRootGroup(values, animator, - (VectorDrawable.VectorDrawableState) target, startTime); - } else { - // Should never get here - throw new UnsupportedOperationException("Target should be either VGroup, VPath, " + - "or ConstantState, " + target.getClass() + " is not supported"); - } - } - - private void createRTAnimatorForGroup(PropertyValuesHolder[] values, - ObjectAnimator animator, VectorDrawable.VGroup target, - long startTime) { - - long nativePtr = target.getNativePtr(); - int propertyId; - for (int i = 0; i < values.length; i++) { - // TODO: We need to support the rare case in AVD where no start value is provided - values[i].getPropertyValues(mTmpValues); - propertyId = VectorDrawable.VGroup.getPropertyIndex(mTmpValues.propertyName); - if (mTmpValues.type != Float.class && mTmpValues.type != float.class) { - if (DBG_ANIMATION_VECTOR_DRAWABLE) { - Log.e(LOGTAG, "Unsupported type: " + - mTmpValues.type + ". Only float value is supported for Groups."); - } - continue; - } - if (propertyId < 0) { - if (DBG_ANIMATION_VECTOR_DRAWABLE) { - Log.e(LOGTAG, "Unsupported property: " + - mTmpValues.propertyName + " for Vector Drawable Group"); - } - continue; - } - long propertyPtr = nCreateGroupPropertyHolder(nativePtr, propertyId, - (Float) mTmpValues.startValue, (Float) mTmpValues.endValue); - if (mTmpValues.dataSource != null) { - float[] dataPoints = createDataPoints(mTmpValues.dataSource, animator - .getDuration()); - nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length); - } - createNativeChildAnimator(propertyPtr, startTime, animator); - } - } - private void createRTAnimatorForPath( ObjectAnimator animator, VectorDrawable.VPath target, - long startTime) { - - long nativePtr = target.getNativePtr(); - long startPathDataPtr = ((PathParser.PathData) mTmpValues.startValue) - .getNativePtr(); - long endPathDataPtr = ((PathParser.PathData) mTmpValues.endValue) - .getNativePtr(); - long propertyPtr = nCreatePathDataPropertyHolder(nativePtr, startPathDataPtr, - endPathDataPtr); - createNativeChildAnimator(propertyPtr, startTime, animator); - } - - private void createRTAnimatorForFullPath(ObjectAnimator animator, - VectorDrawable.VFullPath target, long startTime) { - - int propertyId = target.getPropertyIndex(mTmpValues.propertyName); - long propertyPtr; - long nativePtr = target.getNativePtr(); - if (mTmpValues.type == Float.class || mTmpValues.type == float.class) { - if (propertyId < 0) { - throw new IllegalArgumentException("Property: " + mTmpValues - .propertyName + " is not supported for FullPath"); - } - propertyPtr = nCreatePathPropertyHolder(nativePtr, propertyId, - (Float) mTmpValues.startValue, (Float) mTmpValues.endValue); - - } else if (mTmpValues.type == Integer.class || mTmpValues.type == int.class) { - propertyPtr = nCreatePathColorPropertyHolder(nativePtr, propertyId, - (Integer) mTmpValues.startValue, (Integer) mTmpValues.endValue); - } else { - throw new UnsupportedOperationException("Unsupported type: " + - mTmpValues.type + ". Only float, int or PathData value is " + - "supported for Paths."); - } - if (mTmpValues.dataSource != null) { - float[] dataPoints = createDataPoints(mTmpValues.dataSource, animator - .getDuration()); - nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length); - } - createNativeChildAnimator(propertyPtr, startTime, animator); - } - - private void createRTAnimatorForRootGroup(PropertyValuesHolder[] values, - ObjectAnimator animator, VectorDrawable.VectorDrawableState target, - long startTime) { - long nativePtr = target.getNativeRenderer(); - if (!animator.getPropertyName().equals("alpha")) { - throw new UnsupportedOperationException("Only alpha is supported for root " + - "group"); - } - Float startValue = null; - Float endValue = null; - for (int i = 0; i < values.length; i++) { - values[i].getPropertyValues(mTmpValues); - if (mTmpValues.propertyName.equals("alpha")) { - startValue = (Float) mTmpValues.startValue; - endValue = (Float) mTmpValues.endValue; - break; - } - } - if (startValue == null && endValue == null) { - throw new UnsupportedOperationException("No alpha values are specified"); - } - long propertyPtr = nCreateRootAlphaPropertyHolder(nativePtr, startValue, endValue); - createNativeChildAnimator(propertyPtr, startTime, animator); - } - - // These are the data points that define the value of the animating properties. - // e.g. translateX and translateY can animate along a Path, at any fraction in [0, 1] - // a point on the path corresponds to the values of translateX and translateY. - // TODO: (Optimization) We should pass the path down in native and chop it into segments - // in native. - private static float[] createDataPoints( - PropertyValuesHolder.PropertyValues.DataSource dataSource, long duration) { - long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos(); - int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS); - int numAnimFrames = (int) Math.ceil(((double) duration) / animIntervalMs); - float values[] = new float[numAnimFrames]; - float lastFrame = numAnimFrames - 1; - for (int i = 0; i < numAnimFrames; i++) { - float fraction = i / lastFrame; - values[i] = (Float) dataSource.getValueAtFraction(fraction); - } - return values; - } - - private void createNativeChildAnimator(long propertyPtr, long extraDelay, - ObjectAnimator animator) { - long duration = animator.getDuration(); - int repeatCount = animator.getRepeatCount(); - long startDelay = extraDelay + animator.getStartDelay(); - TimeInterpolator interpolator = animator.getInterpolator(); - long nativeInterpolator = - RenderNodeAnimatorSetHelper.createNativeInterpolator(interpolator, duration); - - startDelay *= ValueAnimator.getDurationScale(); - duration *= ValueAnimator.getDurationScale(); - - mStartDelays.add(startDelay); - nAddAnimator(mSetPtr, propertyPtr, nativeInterpolator, startDelay, duration, - repeatCount); - } - - /** - * Holds a weak reference to the target that was last seen (through the DisplayListCanvas - * in the last draw call), so that when animator set needs to start, we can add the animator - * to the last seen RenderNode target and start right away. - */ - protected void recordLastSeenTarget(DisplayListCanvas canvas) { - if (mAnimationPending) { - mLastSeenTarget = new WeakReference<RenderNode>( - RenderNodeAnimatorSetHelper.getTarget(canvas)); - if (DBG_ANIMATION_VECTOR_DRAWABLE) { - Log.d(LOGTAG, "Target is set in the next frame"); - } - mAnimationPending = false; - start(); - } else { - mLastSeenTarget = new WeakReference<RenderNode>( - RenderNodeAnimatorSetHelper.getTarget(canvas)); - } - - } - - private boolean setTarget(RenderNode node) { - if (mTarget != null && mTarget.get() != null) { - // TODO: Maybe we want to support target change. - throw new IllegalStateException("Target already set!"); - } - - node.addAnimator(this); - mTarget = new WeakReference<RenderNode>(node); - return true; - } - - private boolean useLastSeenTarget() { - if (mLastSeenTarget != null && mLastSeenTarget.get() != null) { - setTarget(mLastSeenTarget.get()); - return true; - } - return false; - } - - public void start() { - if (!mInitialized) { - return; - } - - if (mStarted) { - return; - } - - if (!useLastSeenTarget()) { - mAnimationPending = true; - return; - } - - if (DBG_ANIMATION_VECTOR_DRAWABLE) { - Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java"); - } - - nStart(mSetPtr, this); - if (mListener != null) { - mListener.onAnimationStart(null); - } - mStarted = true; - } - - public void end() { - if (mInitialized && mStarted) { - nEnd(mSetPtr); - onAnimationEnd(); - } - } - - void reset() { - if (!mInitialized) { - return; - } - // TODO: Need to implement reset. - Log.w(LOGTAG, "Reset is yet to be implemented"); - nReset(mSetPtr); - } - - // Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential - // animators or when the animator set has a start delay - void reverse() { - if (!mIsReversible) { - return; - } - // TODO: Need to support reverse (non-public API) - Log.w(LOGTAG, "Reverse is yet to be implemented"); - nReverse(mSetPtr, this); - } - - public long getAnimatorNativePtr() { - return mSetPtr; - } - - boolean canReverse() { - return mIsReversible; - } - - boolean isStarted() { - return mStarted; - } - - boolean isRunning() { - if (!mInitialized) { - return false; - } - return mStarted; - } - - void setListener(AnimatorListener listener) { - mListener = listener; - } - - void removeListener() { - mListener = null; - } - - private void onAnimationEnd() { - mStarted = false; - if (mListener != null) { - mListener.onAnimationEnd(null); - } - mTarget = null; - } - - // onFinished: should be called from native - private static void callOnFinished(VectorDrawableAnimator set) { - if (DBG_ANIMATION_VECTOR_DRAWABLE) { - Log.d(LOGTAG, "on finished called from native"); - } - set.onAnimationEnd(); - } - } - - private static native long nCreateAnimatorSet(); - private static native void nAddAnimator(long setPtr, long propertyValuesHolder, - long nativeInterpolator, long startDelay, long duration, int repeatCount); - - private static native long nCreateGroupPropertyHolder(long nativePtr, int propertyId, - float startValue, float endValue); - - private static native long nCreatePathDataPropertyHolder(long nativePtr, long startValuePtr, - long endValuePtr); - private static native long nCreatePathColorPropertyHolder(long nativePtr, int propertyId, - int startValue, int endValue); - private static native long nCreatePathPropertyHolder(long nativePtr, int propertyId, - float startValue, float endValue); - private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue, - float endValue); - private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length); - private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set); - private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set); - private static native void nEnd(long animatorSetPtr); - private static native void nReset(long animatorSetPtr); } diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index f4bbc8c43d08..1fc1b83f7a6c 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -39,7 +39,6 @@ import android.util.PathParser; import android.util.Xml; import com.android.internal.R; -import com.android.internal.util.VirtualRefBasePtr; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -48,7 +47,6 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.HashMap; import java.util.Stack; /** @@ -524,13 +522,13 @@ public class VectorDrawable extends Drawable { public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { - if (mVectorState.mRootGroup != null || mVectorState.mNativeRendererRefBase != null) { + if (mVectorState.mRootGroup != null || mVectorState.mNativeRendererPtr != 0) { // This VD has been used to display other VD resource content, clean up. mVectorState.mRootGroup = new VGroup(); - if (mVectorState.mNativeRendererRefBase != null) { - mVectorState.mNativeRendererRefBase.release(); + if (mVectorState.mNativeRendererPtr != 0) { + nDestroyRenderer(mVectorState.mNativeRendererPtr); } - mVectorState.createNativeRenderer(mVectorState.mRootGroup.mNativePtr); + mVectorState.mNativeRendererPtr = nCreateRenderer(mVectorState.mRootGroup.mNativePtr); } final VectorDrawableState state = mVectorState; state.setDensity(Drawable.resolveDensity(r, 0)); @@ -709,7 +707,7 @@ public class VectorDrawable extends Drawable { return mVectorState.mAutoMirrored; } - static class VectorDrawableState extends ConstantState { + private static class VectorDrawableState extends ConstantState { // Variables below need to be copied (deep copy if applicable) for mutation. int[] mThemeAttrs; int mChangingConfigurations; @@ -724,7 +722,7 @@ public class VectorDrawable extends Drawable { Insets mOpticalInsets = Insets.NONE; String mRootName = null; VGroup mRootGroup; - VirtualRefBasePtr mNativeRendererRefBase = null; + long mNativeRendererPtr; int mDensity = DisplayMetrics.DENSITY_DEFAULT; final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>(); @@ -745,7 +743,7 @@ public class VectorDrawable extends Drawable { mTintMode = copy.mTintMode; mAutoMirrored = copy.mAutoMirrored; mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap); - createNativeRenderer(mRootGroup.mNativePtr); + mNativeRendererPtr = nCreateRenderer(mRootGroup.mNativePtr); mBaseWidth = copy.mBaseWidth; mBaseHeight = copy.mBaseHeight; @@ -760,15 +758,18 @@ public class VectorDrawable extends Drawable { } } - private void createNativeRenderer(long rootGroupPtr) { - mNativeRendererRefBase = new VirtualRefBasePtr(nCreateRenderer(rootGroupPtr)); + @Override + public void finalize() throws Throwable { + if (mNativeRendererPtr != 0) { + nDestroyRenderer(mNativeRendererPtr); + mNativeRendererPtr = 0; + } + super.finalize(); } + long getNativeRenderer() { - if (mNativeRendererRefBase == null) { - return 0; - } - return mNativeRendererRefBase.get(); + return mNativeRendererPtr; } public boolean canReuseCache() { @@ -807,7 +808,7 @@ public class VectorDrawable extends Drawable { public VectorDrawableState() { mRootGroup = new VGroup(); - createNativeRenderer(mRootGroup.mNativePtr); + mNativeRendererPtr = nCreateRenderer(mRootGroup.mNativePtr); } @Override @@ -871,16 +872,16 @@ public class VectorDrawable extends Drawable { * has changed. */ public boolean setAlpha(float alpha) { - return nSetRootAlpha(mNativeRendererRefBase.get(), alpha); + return nSetRootAlpha(mNativeRendererPtr, alpha); } @SuppressWarnings("unused") public float getAlpha() { - return nGetRootAlpha(mNativeRendererRefBase.get()); + return nGetRootAlpha(mNativeRendererPtr); } } - static class VGroup implements VObject { + private static class VGroup implements VObject { private static final int ROTATE_INDEX = 0; private static final int PIVOT_X_INDEX = 1; private static final int PIVOT_Y_INDEX = 2; @@ -890,28 +891,6 @@ public class VectorDrawable extends Drawable { private static final int TRANSLATE_Y_INDEX = 6; private static final int TRANSFORM_PROPERTY_COUNT = 7; - private static final HashMap<String, Integer> sPropertyMap = - new HashMap<String, Integer>() { - { - put("translateX", TRANSLATE_X_INDEX); - put("translateY", TRANSLATE_Y_INDEX); - put("scaleX", SCALE_X_INDEX); - put("scaleY", SCALE_Y_INDEX); - put("pivotX", PIVOT_X_INDEX); - put("pivotY", PIVOT_Y_INDEX); - put("rotation", ROTATE_INDEX); - } - }; - - static int getPropertyIndex(String propertyName) { - if (sPropertyMap.containsKey(propertyName)) { - return sPropertyMap.get(propertyName); - } else { - // property not found - return -1; - } - } - // Temp array to store transform values obtained from native. private float[] mTransform; ///////////////////////////////////////////////////// @@ -1170,7 +1149,7 @@ public class VectorDrawable extends Drawable { /** * Common Path information for clip path and normal path. */ - static abstract class VPath implements VObject { + private static abstract class VPath implements VObject { protected PathParser.PathData mPathData = null; String mPathName; @@ -1281,7 +1260,7 @@ public class VectorDrawable extends Drawable { /** * Normal path, which contains all the fill / paint information. */ - static class VFullPath extends VPath { + private static class VFullPath extends VPath { private static final int STROKE_WIDTH_INDEX = 0; private static final int STROKE_COLOR_INDEX = 1; private static final int STROKE_ALPHA_INDEX = 2; @@ -1295,20 +1274,6 @@ public class VectorDrawable extends Drawable { private static final int STROKE_MITER_LIMIT_INDEX = 10; private static final int TOTAL_PROPERTY_COUNT = 11; - private final static HashMap<String, Integer> sPropertyMap - = new HashMap<String, Integer> () { - { - put("strokeWidth", STROKE_WIDTH_INDEX); - put("strokeColor", STROKE_COLOR_INDEX); - put("strokeAlpha", STROKE_ALPHA_INDEX); - put("fillColor", FILL_COLOR_INDEX); - put("fillAlpha", FILL_ALPHA_INDEX); - put("trimPathStart", TRIM_PATH_START_INDEX); - put("trimPathEnd", TRIM_PATH_END_INDEX); - put("trimPathOffset", TRIM_PATH_OFFSET_INDEX); - } - }; - // Temp array to store property data obtained from native getter. private byte[] mPropertyData; ///////////////////////////////////////////////////// @@ -1332,14 +1297,6 @@ public class VectorDrawable extends Drawable { mFillColors = copy.mFillColors; } - int getPropertyIndex(String propertyName) { - if (!sPropertyMap.containsKey(propertyName)) { - return -1; - } else { - return sPropertyMap.get(propertyName); - } - } - @Override public boolean onStateChange(int[] stateSet) { boolean changed = false; @@ -1638,6 +1595,7 @@ public class VectorDrawable extends Drawable { } private static native long nCreateRenderer(long rootGroupPtr); + private static native void nDestroyRenderer(long rendererPtr); private static native void nSetRendererViewportSize(long rendererPtr, float viewportWidth, float viewportHeight); private static native boolean nSetRootAlpha(long rendererPtr, float alpha); diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 6988b0294539..1fb9ac515f03 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -78,8 +78,6 @@ hwui_src_files := \ Program.cpp \ ProgramCache.cpp \ Properties.cpp \ - PropertyValuesHolder.cpp \ - PropertyValuesAnimatorSet.cpp \ RenderBufferCache.cpp \ RenderNode.cpp \ RenderProperties.cpp \ @@ -238,6 +236,7 @@ LOCAL_CFLAGS := \ LOCAL_SRC_FILES += \ $(hwui_test_common_src_files) \ + tests/unit/BufferPoolTests.cpp \ tests/unit/CanvasStateTests.cpp \ tests/unit/ClipAreaTests.cpp \ tests/unit/CrashHandlerInjector.cpp \ @@ -247,11 +246,11 @@ LOCAL_SRC_FILES += \ tests/unit/GpuMemoryTrackerTests.cpp \ tests/unit/LayerUpdateQueueTests.cpp \ tests/unit/LinearAllocatorTests.cpp \ - tests/unit/VectorDrawableTests.cpp \ tests/unit/OffscreenBufferPoolTests.cpp \ + tests/unit/SkiaBehaviorTests.cpp \ tests/unit/StringUtilsTests.cpp \ - tests/unit/BufferPoolTests.cpp \ - tests/unit/TextDropShadowCacheTests.cpp + tests/unit/TextDropShadowCacheTests.cpp \ + tests/unit/VectorDrawableTests.cpp ifeq (true, $(HWUI_NEW_OPS)) LOCAL_SRC_FILES += \ diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp index 7bd2b24bf56b..5ca2a2fa37ab 100644 --- a/libs/hwui/Animator.cpp +++ b/libs/hwui/Animator.cpp @@ -90,9 +90,6 @@ void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) { doSetStartValue(getValue(mTarget)); } if (mStagingPlayState > mPlayState) { - if (mStagingPlayState == PlayState::Restarted) { - mStagingPlayState = PlayState::Running; - } mPlayState = mStagingPlayState; // Oh boy, we're starting! Man the battle stations! if (mPlayState == PlayState::Running) { @@ -134,11 +131,6 @@ bool BaseRenderNodeAnimator::animate(AnimationContext& context) { return true; } - // This should be set before setValue() so animators can query this time when setValue - // is called. - nsecs_t currentFrameTime = context.frameTimeMs(); - onPlayTimeChanged(currentFrameTime - mStartTime); - // If BaseRenderNodeAnimator is handling the delay (not typical), then // because the staging properties reflect the final value, we always need // to call setValue even if the animation isn't yet running or is still @@ -149,9 +141,8 @@ bool BaseRenderNodeAnimator::animate(AnimationContext& context) { } float fraction = 1.0f; - if (mPlayState == PlayState::Running && mDuration > 0) { - fraction = (float)(currentFrameTime - mStartTime) / mDuration; + fraction = (float)(context.frameTimeMs() - mStartTime) / mDuration; } if (fraction >= 1.0f) { fraction = 1.0f; diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h index 2c9c9c3fe0f9..aea95bfc1c0e 100644 --- a/libs/hwui/Animator.h +++ b/libs/hwui/Animator.h @@ -59,13 +59,7 @@ public: mMayRunAsync = mayRunAsync; } bool mayRunAsync() { return mMayRunAsync; } - ANDROID_API void start() { - if (mStagingPlayState == PlayState::NotStarted) { - mStagingPlayState = PlayState::Running; - } else { - mStagingPlayState = PlayState::Restarted; - } - onStagingPlayStateChanged(); } + ANDROID_API void start() { mStagingPlayState = PlayState::Running; onStagingPlayStateChanged(); } ANDROID_API void end() { mStagingPlayState = PlayState::Finished; onStagingPlayStateChanged(); } void attach(RenderNode* target); @@ -83,27 +77,10 @@ public: void forceEndNow(AnimationContext& context); protected: - // PlayState is used by mStagingPlayState and mPlayState to track the state initiated from UI - // thread and Render Thread animation state, respectively. - // From the UI thread, mStagingPlayState transition looks like - // NotStarted -> Running -> Finished - // ^ | - // | | - // Restarted <------ - // Note: For mStagingState, the Finished state (optional) is only set when the animation is - // terminated by user. - // - // On Render Thread, mPlayState transition: - // NotStart -> Running -> Finished - // ^ | - // | | - // ------------- - enum class PlayState { NotStarted, Running, Finished, - Restarted, }; BaseRenderNodeAnimator(float finalValue); @@ -116,7 +93,6 @@ protected: void callOnFinishedListener(AnimationContext& context); virtual void onStagingPlayStateChanged() {} - virtual void onPlayTimeChanged(nsecs_t playTime) {} RenderNode* mTarget; diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index 2184755d218a..e3a5f3eeeac1 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -663,7 +663,7 @@ static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, f } void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) { - TessellationCache::vertexBuffer_pair_t buffers = *(op.shadowTask->getResult()); + TessellationCache::vertexBuffer_pair_t buffers = op.shadowTask->getResult(); renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second); } diff --git a/libs/hwui/Canvas.cpp b/libs/hwui/Canvas.cpp index bc88c817ffc8..11ae1a137e2e 100644 --- a/libs/hwui/Canvas.cpp +++ b/libs/hwui/Canvas.cpp @@ -16,10 +16,20 @@ #include "Canvas.h" +#include "DisplayListCanvas.h" +#include "RecordingCanvas.h" #include <SkDrawFilter.h> namespace android { +Canvas* Canvas::create_recording_canvas(int width, int height) { +#if HWUI_NEW_OPS + return new uirenderer::RecordingCanvas(width, height); +#else + return new uirenderer::DisplayListCanvas(width, height); +#endif +} + void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { uint32_t flags; SkDrawFilter* drawFilter = getDrawFilter(); diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h index d7e2f09d4ba1..dbd502d19fd2 100644 --- a/libs/hwui/Canvas.h +++ b/libs/hwui/Canvas.h @@ -18,6 +18,7 @@ #define ANDROID_GRAPHICS_CANVAS_H #include <cutils/compiler.h> +#include <utils/Functor.h> #include "utils/NinePatch.h" @@ -27,6 +28,14 @@ namespace android { +namespace uirenderer { + class CanvasPropertyPaint; + class CanvasPropertyPrimitive; + class DeferredLayerUpdater; + class DisplayList; + class RenderNode; +} + namespace SaveFlags { // These must match the corresponding Canvas API constants. @@ -43,19 +52,14 @@ typedef uint32_t Flags; } // namespace SaveFlags -namespace uirenderer { -namespace VectorDrawable { -class Tree; -}; -}; -typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; - class ANDROID_API Canvas { public: virtual ~Canvas() {}; static Canvas* create_canvas(const SkBitmap& bitmap); + static Canvas* create_recording_canvas(int width, int height); + /** * Create a new Canvas object which delegates to an SkCanvas. * @@ -81,15 +85,36 @@ public: */ virtual SkCanvas* asSkCanvas() = 0; + virtual void setBitmap(const SkBitmap& bitmap) = 0; virtual bool isOpaque() = 0; virtual int width() = 0; virtual int height() = 0; +// ---------------------------------------------------------------------------- +// View System operations (not exposed in public Canvas API) +// ---------------------------------------------------------------------------- + + virtual void resetRecording(int width, int height) = 0; + virtual uirenderer::DisplayList* finishRecording() = 0; + virtual void insertReorderBarrier(bool enableReorder) = 0; + virtual void setHighContrastText(bool highContrastText) = 0; virtual bool isHighContrastText() = 0; + virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left, + uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right, + uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx, + uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) = 0; + virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x, + uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius, + uirenderer::CanvasPropertyPaint* paint) = 0; + + virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0; + virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0; + virtual void callDrawGLFunction(Functor* functor) = 0; + // ---------------------------------------------------------------------------- // Canvas state operations // ---------------------------------------------------------------------------- @@ -192,11 +217,6 @@ public: */ virtual bool drawTextAbsolutePos() const = 0; - /** - * Draws a VectorDrawable onto the canvas. - */ - virtual void drawVectorDrawable(VectorDrawableRoot* tree); - protected: void drawTextDecorations(float x, float y, float length, const SkPaint& paint); }; diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp index 160090dcd8cc..9c08b4dd22ae 100644 --- a/libs/hwui/ClipArea.cpp +++ b/libs/hwui/ClipArea.cpp @@ -213,6 +213,7 @@ void ClipArea::setClip(float left, float top, float right, float bottom) { void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op) { + if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op; onClipUpdated(); switch (mMode) { case ClipMode::Rectangle: @@ -228,6 +229,7 @@ void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform, } void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) { + if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op; onClipUpdated(); enterRegionMode(); mClipRegion.op(region, op); @@ -236,6 +238,7 @@ void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) { void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op) { + if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op; onClipUpdated(); SkMatrix skTransform; transform->copyTo(skTransform); diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h index e44fc20feaa8..250296ecc89f 100644 --- a/libs/hwui/DamageAccumulator.h +++ b/libs/hwui/DamageAccumulator.h @@ -57,7 +57,7 @@ public: // Returns the current dirty area, *NOT* transformed by pushed transforms void peekAtDirty(SkRect* dest) const; - void computeCurrentTransform(Matrix4* outMatrix) const; + ANDROID_API void computeCurrentTransform(Matrix4* outMatrix) const; void finish(SkRect* totalDirty); diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp index 5366127092d4..7eaa78581391 100644 --- a/libs/hwui/DisplayListCanvas.cpp +++ b/libs/hwui/DisplayListCanvas.cpp @@ -16,12 +16,11 @@ #include "DisplayListCanvas.h" +#include "ResourceCache.h" #include "DeferredDisplayList.h" #include "DeferredLayerUpdater.h" #include "DisplayListOp.h" -#include "ResourceCache.h" #include "RenderNode.h" -#include "VectorDrawable.h" #include "utils/PaintUtils.h" #include <SkCamera.h> @@ -42,7 +41,7 @@ DisplayListCanvas::DisplayListCanvas(int width, int height) , mDeferredBarrierType(kBarrier_None) , mHighContrastText(false) , mRestoreSaveCount(-1) { - reset(width, height); + resetRecording(width, height); } DisplayListCanvas::~DisplayListCanvas() { @@ -50,7 +49,7 @@ DisplayListCanvas::~DisplayListCanvas() { "Destroyed a DisplayListCanvas during a record!"); } -void DisplayListCanvas::reset(int width, int height) { +void DisplayListCanvas::resetRecording(int width, int height) { LOG_ALWAYS_FATAL_IF(mDisplayList, "prepareDirty called a second time during a recording!"); mDisplayList = new DisplayList(); @@ -413,16 +412,6 @@ void DisplayListCanvas::drawPoints(const float* points, int count, const SkPaint addDrawOp(new (alloc()) DrawPointsOp(points, count, refPaint(&paint))); } -void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { - mDisplayList->ref(tree); - const SkBitmap& bitmap = tree->getBitmapUpdateIfDirty(); - SkPaint* paint = tree->getPaint(); - const SkRect bounds = tree->getBounds(); - addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap), - 0, 0, bitmap.width(), bitmap.height(), - bounds.left(), bounds.top(), bounds.right(), bounds.bottom(), refPaint(paint))); -} - void DisplayListCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, float hOffset, float vOffset, const SkPaint& paint) { if (!glyphs || count <= 0) return; diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h index d41fff425e81..ad939602ec7d 100644 --- a/libs/hwui/DisplayListCanvas.h +++ b/libs/hwui/DisplayListCanvas.h @@ -67,36 +67,33 @@ public: DisplayListCanvas(int width, int height); virtual ~DisplayListCanvas(); - void reset(int width, int height); - WARN_UNUSED_RESULT DisplayList* finishRecording(); + virtual void resetRecording(int width, int height) override; + virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override; // ---------------------------------------------------------------------------- // HWUI Canvas state operations // ---------------------------------------------------------------------------- - void insertReorderBarrier(bool enableReorder); + virtual void insertReorderBarrier(bool enableReorder) override; // ---------------------------------------------------------------------------- // HWUI Canvas draw operations // ---------------------------------------------------------------------------- // Shapes - void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, + virtual void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, - CanvasPropertyPaint* paint); - void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, - CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint); - + CanvasPropertyPaint* paint) override; + virtual void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, + CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override; // ---------------------------------------------------------------------------- // HWUI Canvas draw operations - special // ---------------------------------------------------------------------------- - void drawLayer(DeferredLayerUpdater* layerHandle); - void drawRenderNode(RenderNode* renderNode); - - // TODO: rename for consistency - void callDrawGLFunction(Functor* functor); + virtual void drawLayer(DeferredLayerUpdater* layerHandle) override; + virtual void drawRenderNode(RenderNode* renderNode) override; + virtual void callDrawGLFunction(Functor* functor) override; // ---------------------------------------------------------------------------- // CanvasStateClient interface @@ -209,8 +206,6 @@ public: float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) override; - virtual void drawVectorDrawable(VectorDrawableRoot* tree) override; - // Text virtual void drawText(const uint16_t* glyphs, const float* positions, int count, const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop, @@ -219,6 +214,7 @@ public: float hOffset, float vOffset, const SkPaint& paint) override; virtual bool drawTextAbsolutePos() const override { return false; } + private: CanvasState mState; diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index 57e5b9d8735a..c8910cbdd337 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -19,7 +19,6 @@ #include "Canvas.h" #include "LayerUpdateQueue.h" #include "RenderNode.h" -#include "VectorDrawable.h" #include "renderstate/OffscreenBufferPool.h" #include "utils/FatVector.h" #include "utils/PaintUtils.h" @@ -203,7 +202,9 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) { mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline())); } - if (!mCanvasState.quickRejectConservative(0, 0, width, height)) { + bool quickRejected = properties.getClipToBounds() + && mCanvasState.quickRejectConservative(0, 0, width, height); + if (!quickRejected) { // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer) if (node.getLayer()) { // HW layer @@ -544,18 +545,6 @@ void FrameBuilder::deferBitmapRectOp(const BitmapRectOp& op) { currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); } -void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) { - const SkBitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty(); - SkPaint* paint = op.vectorDrawable->getPaint(); - const BitmapRectOp* resolvedOp = new (mAllocator) BitmapRectOp(op.unmappedBounds, - op.localMatrix, - op.localClip, - paint, - &bitmap, - Rect(bitmap.width(), bitmap.height())); - deferBitmapRectOp(*resolvedOp); -} - void FrameBuilder::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. diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp deleted file mode 100644 index eca1afcc54dc..000000000000 --- a/libs/hwui/PropertyValuesAnimatorSet.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "PropertyValuesAnimatorSet.h" -#include "RenderNode.h" - -namespace android { -namespace uirenderer { - -void PropertyValuesAnimatorSet::addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder, - Interpolator* interpolator, nsecs_t startDelay, - nsecs_t duration, int repeatCount) { - - PropertyAnimator* animator = new PropertyAnimator(propertyValuesHolder, - interpolator, startDelay, duration, repeatCount); - mAnimators.emplace_back(animator); - setListener(new PropertyAnimatorSetListener(this)); -} - -PropertyValuesAnimatorSet::PropertyValuesAnimatorSet() - : BaseRenderNodeAnimator(1.0f) { - setStartValue(0); - mLastFraction = 0.0f; - setInterpolator(new LinearInterpolator()); -} - -void PropertyValuesAnimatorSet::onFinished(BaseRenderNodeAnimator* animator) { - if (mOneShotListener.get()) { - mOneShotListener->onAnimationFinished(animator); - mOneShotListener = nullptr; - } -} - -float PropertyValuesAnimatorSet::getValue(RenderNode* target) const { - return mLastFraction; -} - -void PropertyValuesAnimatorSet::setValue(RenderNode* target, float value) { - mLastFraction = value; -} - -void PropertyValuesAnimatorSet::onPlayTimeChanged(nsecs_t playTime) { - for (size_t i = 0; i < mAnimators.size(); i++) { - mAnimators[i]->setCurrentPlayTime(playTime); - } -} - -void PropertyValuesAnimatorSet::reset() { - // TODO: implement reset through adding a play state because we need to support reset() even - // during an animation run. -} - -void PropertyValuesAnimatorSet::start(AnimationListener* listener) { - init(); - mOneShotListener = listener; - BaseRenderNodeAnimator::start(); -} - -void PropertyValuesAnimatorSet::reverse(AnimationListener* listener) { -// TODO: implement reverse -} - -void PropertyValuesAnimatorSet::init() { - if (mInitialized) { - return; - } - nsecs_t maxDuration = 0; - for (size_t i = 0; i < mAnimators.size(); i++) { - if (maxDuration < mAnimators[i]->getTotalDuration()) { - maxDuration = mAnimators[i]->getTotalDuration(); - } - } - mDuration = maxDuration; - mInitialized = true; -} - -uint32_t PropertyValuesAnimatorSet::dirtyMask() { - return RenderNode::DISPLAY_LIST; -} - -PropertyAnimator::PropertyAnimator(PropertyValuesHolder* holder, Interpolator* interpolator, - nsecs_t startDelay, nsecs_t duration, int repeatCount) - : mPropertyValuesHolder(holder), mInterpolator(interpolator), mStartDelay(startDelay), - mDuration(duration) { - if (repeatCount < 0) { - mRepeatCount = UINT32_MAX; - } else { - mRepeatCount = repeatCount; - } - mTotalDuration = ((nsecs_t) mRepeatCount + 1) * mDuration + mStartDelay; -} - -void PropertyAnimator::setCurrentPlayTime(nsecs_t playTime) { - if (playTime >= mStartDelay && playTime < mTotalDuration) { - nsecs_t currentIterationPlayTime = (playTime - mStartDelay) % mDuration; - mLatestFraction = currentIterationPlayTime / (float) mDuration; - } else if (mLatestFraction < 1.0f && playTime >= mTotalDuration) { - mLatestFraction = 1.0f; - } else { - return; - } - - setFraction(mLatestFraction); -} - -void PropertyAnimator::setFraction(float fraction) { - float interpolatedFraction = mInterpolator->interpolate(mLatestFraction); - mPropertyValuesHolder->setFraction(interpolatedFraction); -} - -void PropertyAnimatorSetListener::onAnimationFinished(BaseRenderNodeAnimator* animator) { - mSet->onFinished(animator); -} - -} -} diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h deleted file mode 100644 index 4c7ce528bb20..000000000000 --- a/libs/hwui/PropertyValuesAnimatorSet.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Animator.h" -#include "PropertyValuesHolder.h" -#include "Interpolator.h" - -namespace android { -namespace uirenderer { - -class PropertyAnimator { -public: - PropertyAnimator(PropertyValuesHolder* holder, Interpolator* interpolator, nsecs_t startDelay, - nsecs_t duration, int repeatCount); - void setCurrentPlayTime(nsecs_t playTime); - nsecs_t getTotalDuration() { - return mTotalDuration; - } - void setFraction(float fraction); - -private: - std::unique_ptr<PropertyValuesHolder> mPropertyValuesHolder; - std::unique_ptr<Interpolator> mInterpolator; - nsecs_t mStartDelay; - nsecs_t mDuration; - uint32_t mRepeatCount; - nsecs_t mTotalDuration; - float mLatestFraction = 0.0f; -}; - -class ANDROID_API PropertyValuesAnimatorSet : public BaseRenderNodeAnimator { -public: - friend class PropertyAnimatorSetListener; - PropertyValuesAnimatorSet(); - - void start(AnimationListener* listener); - void reverse(AnimationListener* listener); - void reset(); - - void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder, - Interpolator* interpolators, int64_t startDelays, - nsecs_t durations, int repeatCount); - virtual uint32_t dirtyMask(); - -protected: - virtual float getValue(RenderNode* target) const override; - virtual void setValue(RenderNode* target, float value) override; - virtual void onPlayTimeChanged(nsecs_t playTime) override; - -private: - void init(); - void onFinished(BaseRenderNodeAnimator* animator); - // Listener set from outside - sp<AnimationListener> mOneShotListener; - std::vector< std::unique_ptr<PropertyAnimator> > mAnimators; - float mLastFraction = 0.0f; - bool mInitialized = false; -}; - -class PropertyAnimatorSetListener : public AnimationListener { -public: - PropertyAnimatorSetListener(PropertyValuesAnimatorSet* set) : mSet(set) {} - virtual void onAnimationFinished(BaseRenderNodeAnimator* animator) override; - -private: - PropertyValuesAnimatorSet* mSet; -}; - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/PropertyValuesHolder.cpp b/libs/hwui/PropertyValuesHolder.cpp deleted file mode 100644 index 8f837f6048d6..000000000000 --- a/libs/hwui/PropertyValuesHolder.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "PropertyValuesHolder.h" - -#include "utils/VectorDrawableUtils.h" - -#include <utils/Log.h> - -namespace android { -namespace uirenderer { - -using namespace VectorDrawable; - -float PropertyValuesHolder::getValueFromData(float fraction) { - if (mDataSource.size() == 0) { - LOG_ALWAYS_FATAL("No data source is defined"); - return 0; - } - if (fraction <= 0.0f) { - return mDataSource.front(); - } - if (fraction >= 1.0f) { - return mDataSource.back(); - } - - fraction *= mDataSource.size() - 1; - int lowIndex = floor(fraction); - fraction -= lowIndex; - - float value = mDataSource[lowIndex] * (1.0f - fraction) - + mDataSource[lowIndex + 1] * fraction; - return value; -} - -void GroupPropertyValuesHolder::setFraction(float fraction) { - float animatedValue; - if (mDataSource.size() > 0) { - animatedValue = getValueFromData(fraction); - } else { - animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction; - } - mGroup->setPropertyValue(mPropertyId, animatedValue); -} - -inline U8CPU lerp(U8CPU fromValue, U8CPU toValue, float fraction) { - return (U8CPU) (fromValue * (1 - fraction) + toValue * fraction); -} - -// TODO: Add a test for this -SkColor FullPathColorPropertyValuesHolder::interpolateColors(SkColor fromColor, SkColor toColor, - float fraction) { - U8CPU alpha = lerp(SkColorGetA(fromColor), SkColorGetA(toColor), fraction); - U8CPU red = lerp(SkColorGetR(fromColor), SkColorGetR(toColor), fraction); - U8CPU green = lerp(SkColorGetG(fromColor), SkColorGetG(toColor), fraction); - U8CPU blue = lerp(SkColorGetB(fromColor), SkColorGetB(toColor), fraction); - return SkColorSetARGB(alpha, red, green, blue); -} - -void FullPathColorPropertyValuesHolder::setFraction(float fraction) { - SkColor animatedValue = interpolateColors(mStartValue, mEndValue, fraction); - mFullPath->setColorPropertyValue(mPropertyId, animatedValue); -} - -void FullPathPropertyValuesHolder::setFraction(float fraction) { - float animatedValue; - if (mDataSource.size() > 0) { - animatedValue = getValueFromData(fraction); - } else { - animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction; - } - mFullPath->setPropertyValue(mPropertyId, animatedValue); -} - -void PathDataPropertyValuesHolder::setFraction(float fraction) { - VectorDrawableUtils::interpolatePaths(&mPathData, mStartValue, mEndValue, fraction); - mPath->setPathData(mPathData); -} - -void RootAlphaPropertyValuesHolder::setFraction(float fraction) { - float animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction; - mTree->setRootAlpha(animatedValue); -} - -} // namepace uirenderer -} // namespace android diff --git a/libs/hwui/PropertyValuesHolder.h b/libs/hwui/PropertyValuesHolder.h deleted file mode 100644 index b905faef104c..000000000000 --- a/libs/hwui/PropertyValuesHolder.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "VectorDrawable.h" - -#include <SkColor.h> - -namespace android { -namespace uirenderer { - -/** - * PropertyValues holder contains data needed to change a property of a Vector Drawable object. - * When a fraction in [0f, 1f] is provided, the holder will calculate an interpolated value based - * on its start and end value, and set the new value on the VectorDrawble's corresponding property. - */ -class ANDROID_API PropertyValuesHolder { -public: - virtual void setFraction(float fraction) = 0; - void setPropertyDataSource(float* dataSource, int length) { - mDataSource.insert(mDataSource.begin(), dataSource, dataSource + length); - } - float getValueFromData(float fraction); - virtual ~PropertyValuesHolder() {} -protected: - std::vector<float> mDataSource; -}; - -class ANDROID_API GroupPropertyValuesHolder : public PropertyValuesHolder { -public: - GroupPropertyValuesHolder(VectorDrawable::Group* ptr, int propertyId, float startValue, - float endValue) - : mGroup(ptr) - , mPropertyId(propertyId) - , mStartValue(startValue) - , mEndValue(endValue){ - } - void setFraction(float fraction) override; -private: - VectorDrawable::Group* mGroup; - int mPropertyId; - float mStartValue; - float mEndValue; -}; - -class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolder { -public: - FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, int32_t startValue, - int32_t endValue) - : mFullPath(ptr) - , mPropertyId(propertyId) - , mStartValue(startValue) - , mEndValue(endValue) {}; - void setFraction(float fraction) override; - static SkColor interpolateColors(SkColor fromColor, SkColor toColor, float fraction); -private: - VectorDrawable::FullPath* mFullPath; - int mPropertyId; - int32_t mStartValue; - int32_t mEndValue; -}; - -class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolder { -public: - FullPathPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, float startValue, - float endValue) - : mFullPath(ptr) - , mPropertyId(propertyId) - , mStartValue(startValue) - , mEndValue(endValue) {}; - void setFraction(float fraction) override; -private: - VectorDrawable::FullPath* mFullPath; - int mPropertyId; - float mStartValue; - float mEndValue; -}; - -class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolder { -public: - PathDataPropertyValuesHolder(VectorDrawable::Path* ptr, PathData* startValue, - PathData* endValue) - : mPath(ptr) - , mStartValue(*startValue) - , mEndValue(*endValue) {}; - void setFraction(float fraction) override; -private: - VectorDrawable::Path* mPath; - PathData mPathData; - PathData mStartValue; - PathData mEndValue; -}; - -class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolder { -public: - RootAlphaPropertyValuesHolder(VectorDrawable::Tree* tree, float startValue, float endValue) - : mTree(tree) - , mStartValue(startValue) - , mEndValue(endValue) {} - void setFraction(float fraction) override; -private: - VectorDrawable::Tree* mTree; - float mStartValue; - float mEndValue; -}; -} -} diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index bb26e2ec67a8..593d690f2b43 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -17,7 +17,6 @@ #ifndef ANDROID_HWUI_RECORDED_OP_H #define ANDROID_HWUI_RECORDED_OP_H -#include "RecordedOp.h" #include "font/FontUtil.h" #include "Matrix.h" #include "Rect.h" @@ -40,10 +39,6 @@ class OffscreenBuffer; class RenderNode; struct Vertex; -namespace VectorDrawable { -class Tree; -} - /** * Authoritative op list, used for generating the op ID enum, ID based LUTS, and * the functions to which they dispatch. Parameter macros are executed for each op, @@ -80,7 +75,6 @@ class Tree; PRE_RENDER_OP_FN(EndLayerOp) \ PRE_RENDER_OP_FN(BeginUnclippedLayerOp) \ PRE_RENDER_OP_FN(EndUnclippedLayerOp) \ - PRE_RENDER_OP_FN(VectorDrawableOp) \ \ RENDER_ONLY_OP_FN(ShadowOp) \ RENDER_ONLY_OP_FN(LayerOp) \ @@ -331,13 +325,6 @@ struct RoundRectPropsOp : RecordedOp { const float* ry; }; -struct VectorDrawableOp : RecordedOp { - VectorDrawableOp(VectorDrawable::Tree* tree, BASE_PARAMS_PAINTLESS) - : SUPER_PAINTLESS(VectorDrawableOp) - , vectorDrawable(tree) {} - VectorDrawable::Tree* vectorDrawable; -}; - /** * Real-time, dynamic-lit shadow. * diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index abbd9c38d0ad..2387962cc795 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -19,7 +19,6 @@ #include "DeferredLayerUpdater.h" #include "RecordedOp.h" #include "RenderNode.h" -#include "VectorDrawable.h" namespace android { namespace uirenderer { @@ -27,7 +26,7 @@ namespace uirenderer { RecordingCanvas::RecordingCanvas(size_t width, size_t height) : mState(*this) , mResourceCache(ResourceCache::getInstance()) { - reset(width, height); + resetRecording(width, height); } RecordingCanvas::~RecordingCanvas() { @@ -35,7 +34,7 @@ RecordingCanvas::~RecordingCanvas() { "Destroyed a RecordingCanvas during a record!"); } -void RecordingCanvas::reset(int width, int height) { +void RecordingCanvas::resetRecording(int width, int height) { LOG_ALWAYS_FATAL_IF(mDisplayList, "prepareDirty called a second time during a recording!"); mDisplayList = new DisplayList(); @@ -396,6 +395,7 @@ void RecordingCanvas::drawCircle( &x->value, &y->value, &radius->value)); } + void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) { addOp(new (alloc()) OvalOp( Rect(left, top, right, bottom), @@ -422,15 +422,6 @@ void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) { refPaint(&paint), refPath(&path))); } -void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { - mDisplayList->ref(tree); - addOp(new (alloc()) VectorDrawableOp( - tree, - Rect(tree->getBounds()), - *(mState.currentSnapshot()->transform), - getRecordedClip())); -} - // Bitmap-based void RecordingCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) { save(SaveFlags::Matrix); diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index 7c8ad8814d32..375760f2dd81 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -50,22 +50,19 @@ public: RecordingCanvas(size_t width, size_t height); virtual ~RecordingCanvas(); - void reset(int width, int height); - WARN_UNUSED_RESULT DisplayList* finishRecording(); - + virtual void resetRecording(int width, int height) override; + virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override; // ---------------------------------------------------------------------------- // MISC HWUI OPERATIONS - TODO: CATEGORIZE // ---------------------------------------------------------------------------- - void insertReorderBarrier(bool enableReorder) { + virtual void insertReorderBarrier(bool enableReorder) override { mDeferredBarrierType = enableReorder ? DeferredBarrierType::OutOfOrder : DeferredBarrierType::InOrder; } - void drawLayer(DeferredLayerUpdater* layerHandle); - void drawRenderNode(RenderNode* renderNode); - - // TODO: rename for consistency - void callDrawGLFunction(Functor* functor); + virtual void drawLayer(DeferredLayerUpdater* layerHandle) override; + virtual void drawRenderNode(RenderNode* renderNode) override; + virtual void callDrawGLFunction(Functor* functor) override; // ---------------------------------------------------------------------------- // CanvasStateClient interface @@ -78,12 +75,12 @@ public: // HWUI Canvas draw operations // ---------------------------------------------------------------------------- - void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, + virtual void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, - CanvasPropertyPaint* paint); - void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, - CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint); + CanvasPropertyPaint* paint) override; + virtual void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, + CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override; // ---------------------------------------------------------------------------- // android/graphics/Canvas interface @@ -178,8 +175,6 @@ public: const uint16_t* indices, int indexCount, const SkPaint& paint) override { /* RecordingCanvas does not support drawVertices(); ignore */ } - virtual void drawVectorDrawable(VectorDrawableRoot* tree) override; - // Bitmap-based virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) override; virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d4588edea207..bade216b3b21 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -381,6 +381,10 @@ void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) { bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence( willHaveFunctor, functorsNeedLayer); + if (CC_UNLIKELY(mPositionListener.get())) { + mPositionListener->onPositionUpdated(*this, info); + } + prepareLayer(info, animatorDirtyMask); if (info.mode == TreeInfo::MODE_FULL) { pushStagingDisplayListChanges(info); diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 8e4a3df271f5..f248de54acba 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -209,6 +209,19 @@ public: OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh... #endif + class ANDROID_API PositionListener { + public: + virtual ~PositionListener() {} + virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) = 0; + }; + + // Note this is not thread safe, this needs to be called + // before the RenderNode is used for drawing. + // RenderNode takes ownership of the pointer + ANDROID_API void setPositionListener(PositionListener* listener) { + mPositionListener.reset(listener); + } + private: typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair; @@ -317,6 +330,8 @@ private: // This is *NOT* thread-safe, and should therefore only be tracking // mDisplayList, not mStagingDisplayList. uint32_t mParentCount; + + std::unique_ptr<PositionListener> mPositionListener; }; // class RenderNode } /* namespace uirenderer */ diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 550995b2b9c6..d320a410bc84 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -15,20 +15,23 @@ */ #include "Canvas.h" +#include "CanvasProperty.h" +#include "Layer.h" +#include "RenderNode.h" #include <SkCanvas.h> #include <SkClipStack.h> +#include <SkDrawable.h> #include <SkDevice.h> #include <SkDeque.h> #include <SkDrawFilter.h> #include <SkGraphics.h> +#include <SkImage.h> #include <SkShader.h> #include <SkTArray.h> #include <SkTLazy.h> #include <SkTemplates.h> -#include "VectorDrawable.h" - #include <memory> namespace android { @@ -54,6 +57,18 @@ public: return mCanvas.get(); } + virtual void resetRecording(int width, int height) override { + LOG_ALWAYS_FATAL("SkiaCanvas cannot be reset as a recording canvas"); + } + + virtual uirenderer::DisplayList* finishRecording() override { + LOG_ALWAYS_FATAL("SkiaCanvas does not produce a DisplayList"); + return nullptr; + } + virtual void insertReorderBarrier(bool enableReorder) override { + LOG_ALWAYS_FATAL("SkiaCanvas does not support reordering barriers"); + } + virtual void setBitmap(const SkBitmap& bitmap) override; virtual bool isOpaque() override; @@ -138,7 +153,18 @@ public: float hOffset, float vOffset, const SkPaint& paint) override; virtual bool drawTextAbsolutePos() const override { return true; } - virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override; + + virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left, + uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right, + uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx, + uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) override; + virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x, + uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius, + uirenderer::CanvasPropertyPaint* paint) override; + + virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override; + virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override; + virtual void callDrawGLFunction(Functor* functor) override; private: struct SaveRec { @@ -716,14 +742,6 @@ void SkiaCanvas::drawNinePatch(const SkBitmap& bitmap, const Res_png_9patch& chu NinePatch::Draw(mCanvas, bounds, bitmap, chunk, paint, nullptr); } -void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) { - const SkBitmap& bitmap = vectorDrawable->getBitmapUpdateIfDirty(); - SkRect bounds = vectorDrawable->getBounds(); - drawBitmap(bitmap, 0, 0, bitmap.width(), bitmap.height(), - bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, - vectorDrawable->getPaint()); -} - // ---------------------------------------------------------------------------- // Canvas draw operations: Text // ---------------------------------------------------------------------------- @@ -748,4 +766,84 @@ void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& mCanvas->drawTextOnPathHV(glyphs, count << 1, path, hOffset, vOffset, paint); } +// ---------------------------------------------------------------------------- +// Canvas draw operations: Animations +// ---------------------------------------------------------------------------- + +class AnimatedRoundRect : public SkDrawable { + public: + AnimatedRoundRect(uirenderer::CanvasPropertyPrimitive* left, + uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right, + uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx, + uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* p) : + mLeft(left), mTop(top), mRight(right), mBottom(bottom), mRx(rx), mRy(ry), mPaint(p) {} + + protected: + virtual SkRect onGetBounds() override { + return SkRect::MakeLTRB(mLeft->value, mTop->value, mRight->value, mBottom->value); + } + virtual void onDraw(SkCanvas* canvas) override { + SkRect rect = SkRect::MakeLTRB(mLeft->value, mTop->value, mRight->value, mBottom->value); + canvas->drawRoundRect(rect, mRx->value, mRy->value, mPaint->value); + } + + private: + sp<uirenderer::CanvasPropertyPrimitive> mLeft; + sp<uirenderer::CanvasPropertyPrimitive> mTop; + sp<uirenderer::CanvasPropertyPrimitive> mRight; + sp<uirenderer::CanvasPropertyPrimitive> mBottom; + sp<uirenderer::CanvasPropertyPrimitive> mRx; + sp<uirenderer::CanvasPropertyPrimitive> mRy; + sp<uirenderer::CanvasPropertyPaint> mPaint; +}; + +class AnimatedCircle : public SkDrawable { + public: + AnimatedCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y, + uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) : + mX(x), mY(y), mRadius(radius), mPaint(paint) {} + + protected: + virtual SkRect onGetBounds() override { + const float x = mX->value; + const float y = mY->value; + const float radius = mRadius->value; + return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius); + } + virtual void onDraw(SkCanvas* canvas) override { + canvas->drawCircle(mX->value, mY->value, mRadius->value, mPaint->value); + } + + private: + sp<uirenderer::CanvasPropertyPrimitive> mX; + sp<uirenderer::CanvasPropertyPrimitive> mY; + sp<uirenderer::CanvasPropertyPrimitive> mRadius; + sp<uirenderer::CanvasPropertyPaint> mPaint; +}; + +void SkiaCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left, + uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right, + uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx, + uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) { + SkAutoTUnref<AnimatedRoundRect> drawable( + new AnimatedRoundRect(left, top, right, bottom, rx, ry, paint)); + mCanvas->drawDrawable(drawable.get()); +} + +void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y, + uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) { + SkAutoTUnref<AnimatedCircle> drawable(new AnimatedCircle(x, y, radius, paint)); + mCanvas->drawDrawable(drawable.get()); +} + +// ---------------------------------------------------------------------------- +// Canvas draw operations: View System +// ---------------------------------------------------------------------------- + +void SkiaCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layer) { } + +void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { } + +void SkiaCanvas::callDrawGLFunction(Functor* functor) { } + } // namespace android diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp index 461e8190c974..fd9fb852171c 100644 --- a/libs/hwui/TessellationCache.cpp +++ b/libs/hwui/TessellationCache.cpp @@ -242,23 +242,21 @@ void tessellateShadows( spotBuffer); } -class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t*> { +class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t> { public: ShadowProcessor(Caches& caches) - : TaskProcessor<TessellationCache::vertexBuffer_pair_t*>(&caches.tasks) {} + : TaskProcessor<TessellationCache::vertexBuffer_pair_t>(&caches.tasks) {} ~ShadowProcessor() {} - virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) override { + virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t> >& task) override { TessellationCache::ShadowTask* t = static_cast<TessellationCache::ShadowTask*>(task.get()); ATRACE_NAME("shadow tessellation"); - VertexBuffer* ambientBuffer = new VertexBuffer; - VertexBuffer* spotBuffer = new VertexBuffer; tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter, &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius, - *ambientBuffer, *spotBuffer); + t->ambientBuffer, t->spotBuffer); - t->setResult(new TessellationCache::vertexBuffer_pair_t(ambientBuffer, spotBuffer)); + t->setResult(TessellationCache::vertexBuffer_pair_t(&t->ambientBuffer, &t->spotBuffer)); } }; @@ -373,7 +371,7 @@ void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rec task = static_cast<ShadowTask*>(mShadowCache.get(key)); } LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached"); - outBuffers = *(task->getResult()); + outBuffers = task->getResult(); } sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask( @@ -392,13 +390,6 @@ sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask( return task; } -TessellationCache::ShadowTask::~ShadowTask() { - TessellationCache::vertexBuffer_pair_t* bufferPair = getResult(); - delete bufferPair->getFirst(); - delete bufferPair->getSecond(); - delete bufferPair; -} - /////////////////////////////////////////////////////////////////////////////// // Tessellation precaching /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h index 977c2d9e9f8a..6dcc8120cf48 100644 --- a/libs/hwui/TessellationCache.h +++ b/libs/hwui/TessellationCache.h @@ -21,6 +21,7 @@ #include "Matrix.h" #include "Rect.h" #include "Vector.h" +#include "VertexBuffer.h" #include "thread/TaskProcessor.h" #include "utils/Macros.h" #include "utils/Pair.h" @@ -89,7 +90,7 @@ public: hash_t hash() const; }; - class ShadowTask : public Task<TessellationCache::vertexBuffer_pair_t*> { + class ShadowTask : public Task<vertexBuffer_pair_t> { public: ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque, const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ, @@ -104,13 +105,11 @@ public: , lightRadius(lightRadius) { } - ~ShadowTask(); - /* Note - we deep copy all task parameters, because *even though* pointers into Allocator * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame, * certain Allocators are destroyed before trim() is called to flush incomplete tasks. * - * These deep copies could be avoided, long term, by cancelling or flushing outstanding + * These deep copies could be avoided, long term, by canceling or flushing outstanding * tasks before tearing down single-frame LinearAllocators. */ const Matrix4 drawTransform; @@ -121,6 +120,8 @@ public: const Matrix4 transformZ; const Vector3 lightCenter; const float lightRadius; + VertexBuffer ambientBuffer; + VertexBuffer spotBuffer; }; TessellationCache(); @@ -217,12 +218,12 @@ private: /////////////////////////////////////////////////////////////////////////////// // Shadow tessellation caching /////////////////////////////////////////////////////////////////////////////// - sp<TaskProcessor<vertexBuffer_pair_t*> > mShadowProcessor; + sp<TaskProcessor<vertexBuffer_pair_t> > mShadowProcessor; // holds a pointer, and implicit strong ref to each shadow task of the frame - LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*> mShadowCache; - class BufferPairRemovedListener : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t*>*> { - void operator()(ShadowDescription& description, Task<vertexBuffer_pair_t*>*& bufferPairTask) override { + LruCache<ShadowDescription, Task<vertexBuffer_pair_t>*> mShadowCache; + class BufferPairRemovedListener : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t>*> { + void operator()(ShadowDescription& description, Task<vertexBuffer_pair_t>*& bufferPairTask) override { bufferPairTask->decStrong(nullptr); } }; diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index be25516c587a..accd3038cb9c 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -86,6 +86,12 @@ public: #endif ErrorHandler* errorHandler = nullptr; + // Frame number for use with synchronized surfaceview position updating + int64_t frameNumber = -1; + int32_t windowInsetLeft = 0; + int32_t windowInsetTop = 0; + bool updateWindowPositions = false; + struct Out { bool hasFunctors = false; // This is only updated if evaluateAnimations is true diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp index c72f87d7e481..1cf15ac01154 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -138,7 +138,18 @@ void Path::setPath(const char* pathStr, size_t strLength) { } FullPath::FullPath(const FullPath& path) : Path(path) { - mProperties = path.mProperties; + mStrokeWidth = path.mStrokeWidth; + mStrokeColor = path.mStrokeColor; + mStrokeAlpha = path.mStrokeAlpha; + mFillColor = path.mFillColor; + mFillAlpha = path.mFillAlpha; + mTrimPathStart = path.mTrimPathStart; + mTrimPathEnd = path.mTrimPathEnd; + mTrimPathOffset = path.mTrimPathOffset; + mStrokeMiterLimit = path.mStrokeMiterLimit; + mStrokeLineCap = path.mStrokeLineCap; + mStrokeLineJoin = path.mStrokeLineJoin; + SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient); SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient); } @@ -148,7 +159,7 @@ const SkPath& FullPath::getUpdatedPath() { return mTrimmedSkPath; } Path::getUpdatedPath(); - if (mProperties.trimPathStart != 0.0f || mProperties.trimPathEnd != 1.0f) { + if (mTrimPathStart != 0.0f || mTrimPathEnd != 1.0f) { applyTrim(); return mTrimmedSkPath; } else { @@ -159,14 +170,14 @@ const SkPath& FullPath::getUpdatedPath() { void FullPath::updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha, SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin) { - mProperties.strokeWidth = strokeWidth; - mProperties.strokeColor = strokeColor; - mProperties.strokeAlpha = strokeAlpha; - mProperties.fillColor = fillColor; - mProperties.fillAlpha = fillAlpha; - mProperties.strokeMiterLimit = strokeMiterLimit; - mProperties.strokeLineCap = strokeLineCap; - mProperties.strokeLineJoin = strokeLineJoin; + mStrokeWidth = strokeWidth; + mStrokeColor = strokeColor; + mStrokeAlpha = strokeAlpha; + mFillColor = fillColor; + mFillAlpha = fillAlpha; + mStrokeMiterLimit = strokeMiterLimit; + mStrokeLineCap = SkPaint::Cap(strokeLineCap); + mStrokeLineJoin = SkPaint::Join(strokeLineJoin); // If any trim property changes, mark trim dirty and update the trim path setTrimPathStart(trimPathStart); @@ -184,12 +195,12 @@ void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float str // Draw path's fill, if fill color or gradient is valid bool needsFill = false; if (mFillGradient != nullptr) { - mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.fillAlpha)); + mPaint.setColor(applyAlpha(SK_ColorBLACK, mFillAlpha)); SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix); mPaint.setShader(newShader); needsFill = true; - } else if (mProperties.fillColor != SK_ColorTRANSPARENT) { - mPaint.setColor(applyAlpha(mProperties.fillColor, mProperties.fillAlpha)); + } else if (mFillColor != SK_ColorTRANSPARENT) { + mPaint.setColor(applyAlpha(mFillColor, mFillAlpha)); needsFill = true; } @@ -202,21 +213,21 @@ void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float str // Draw path's stroke, if stroke color or gradient is valid bool needsStroke = false; if (mStrokeGradient != nullptr) { - mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.strokeAlpha)); + mPaint.setColor(applyAlpha(SK_ColorBLACK, mStrokeAlpha)); SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix); mPaint.setShader(newShader); needsStroke = true; - } else if (mProperties.strokeColor != SK_ColorTRANSPARENT) { - mPaint.setColor(applyAlpha(mProperties.strokeColor, mProperties.strokeAlpha)); + } else if (mStrokeColor != SK_ColorTRANSPARENT) { + mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha)); needsStroke = true; } if (needsStroke) { mPaint.setStyle(SkPaint::Style::kStroke_Style); mPaint.setAntiAlias(true); - mPaint.setStrokeJoin(SkPaint::Join(mProperties.strokeLineJoin)); - mPaint.setStrokeCap(SkPaint::Cap(mProperties.strokeLineCap)); - mPaint.setStrokeMiter(mProperties.strokeMiterLimit); - mPaint.setStrokeWidth(mProperties.strokeWidth * strokeScale); + mPaint.setStrokeJoin(mStrokeLineJoin); + mPaint.setStrokeCap(mStrokeLineCap); + mPaint.setStrokeMiter(mStrokeMiterLimit); + mPaint.setStrokeWidth(mStrokeWidth * strokeScale); outCanvas->drawPath(renderPath, mPaint); } } @@ -225,14 +236,14 @@ void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float str * Applies trimming to the specified path. */ void FullPath::applyTrim() { - if (mProperties.trimPathStart == 0.0f && mProperties.trimPathEnd == 1.0f) { + if (mTrimPathStart == 0.0f && mTrimPathEnd == 1.0f) { // No trimming necessary. return; } SkPathMeasure measure(mSkPath, false); float len = SkScalarToFloat(measure.getLength()); - float start = len * fmod((mProperties.trimPathStart + mProperties.trimPathOffset), 1.0f); - float end = len * fmod((mProperties.trimPathEnd + mProperties.trimPathOffset), 1.0f); + float start = len * fmod((mTrimPathStart + mTrimPathOffset), 1.0f); + float end = len * fmod((mTrimPathEnd + mTrimPathOffset), 1.0f); mTrimmedSkPath.reset(); if (start > end) { @@ -244,69 +255,76 @@ void FullPath::applyTrim() { mTrimDirty = false; } -REQUIRE_COMPATIBLE_LAYOUT(FullPath::Properties); +inline int putData(int8_t* outBytes, int startIndex, float value) { + int size = sizeof(float); + memcpy(&outBytes[startIndex], &value, size); + return size; +} + +inline int putData(int8_t* outBytes, int startIndex, int value) { + int size = sizeof(int); + memcpy(&outBytes[startIndex], &value, size); + return size; +} + +struct FullPathProperties { + // TODO: Consider storing full path properties in this struct instead of the fields. + float strokeWidth; + SkColor strokeColor; + float strokeAlpha; + SkColor fillColor; + float fillAlpha; + float trimPathStart; + float trimPathEnd; + float trimPathOffset; + int32_t strokeLineCap; + int32_t strokeLineJoin; + float strokeMiterLimit; +}; + +REQUIRE_COMPATIBLE_LAYOUT(FullPathProperties); static_assert(sizeof(float) == sizeof(int32_t), "float is not the same size as int32_t"); static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor is not the same size as int32_t"); bool FullPath::getProperties(int8_t* outProperties, int length) { - int propertyDataSize = sizeof(Properties); + int propertyDataSize = sizeof(FullPathProperties); if (length != propertyDataSize) { LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided", propertyDataSize, length); return false; } - Properties* out = reinterpret_cast<Properties*>(outProperties); - *out = mProperties; + // TODO: consider replacing the property fields with a FullPathProperties struct. + FullPathProperties properties; + properties.strokeWidth = mStrokeWidth; + properties.strokeColor = mStrokeColor; + properties.strokeAlpha = mStrokeAlpha; + properties.fillColor = mFillColor; + properties.fillAlpha = mFillAlpha; + properties.trimPathStart = mTrimPathStart; + properties.trimPathEnd = mTrimPathEnd; + properties.trimPathOffset = mTrimPathOffset; + properties.strokeLineCap = mStrokeLineCap; + properties.strokeLineJoin = mStrokeLineJoin; + properties.strokeMiterLimit = mStrokeMiterLimit; + + memcpy(outProperties, &properties, length); return true; } -void FullPath::setColorPropertyValue(int propertyId, int32_t value) { - Property currentProperty = static_cast<Property>(propertyId); - if (currentProperty == Property::StrokeColor) { - mProperties.strokeColor = value; - } else if (currentProperty == Property::FillColor) { - mProperties.fillColor = value; - } else { - LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property with id: %d", - propertyId); - } -} - -void FullPath::setPropertyValue(int propertyId, float value) { - Property property = static_cast<Property>(propertyId); - switch (property) { - case Property::StrokeWidth: - setStrokeWidth(value); - break; - case Property::StrokeAlpha: - setStrokeAlpha(value); - break; - case Property::FillAlpha: - setFillAlpha(value); - break; - case Property::TrimPathStart: - setTrimPathStart(value); - break; - case Property::TrimPathEnd: - setTrimPathEnd(value); - break; - case Property::TrimPathOffset: - setTrimPathOffset(value); - break; - default: - LOG_ALWAYS_FATAL("Invalid property id: %d for animation", propertyId); - break; - } -} - void ClipPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale, const SkMatrix& matrix){ outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op); } Group::Group(const Group& group) : Node(group) { - mProperties = group.mProperties; + mRotate = group.mRotate; + mPivotX = group.mPivotX; + mPivotY = group.mPivotY; + mScaleX = group.mScaleX; + mScaleY = group.mScaleY; + mTranslateX = group.mTranslateX; + mTranslateY = group.mTranslateY; } void Group::draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, float scaleX, @@ -353,11 +371,10 @@ void Group::getLocalMatrix(SkMatrix* outMatrix) { outMatrix->reset(); // TODO: use rotate(mRotate, mPivotX, mPivotY) and scale with pivot point, instead of // translating to pivot for rotating and scaling, then translating back. - outMatrix->postTranslate(-mProperties.pivotX, -mProperties.pivotY); - outMatrix->postScale(mProperties.scaleX, mProperties.scaleY); - outMatrix->postRotate(mProperties.rotate, 0, 0); - outMatrix->postTranslate(mProperties.translateX + mProperties.pivotX, - mProperties.translateY + mProperties.pivotY); + outMatrix->postTranslate(-mPivotX, -mPivotY); + outMatrix->postScale(mScaleX, mScaleY); + outMatrix->postRotate(mRotate, 0, 0); + outMatrix->postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY); } void Group::addChild(Node* child) { @@ -371,66 +388,36 @@ bool Group::getProperties(float* outProperties, int length) { propertyCount, length); return false; } - Properties* out = reinterpret_cast<Properties*>(outProperties); - *out = mProperties; - return true; -} - -// TODO: Consider animating the properties as float pointers -float Group::getPropertyValue(int propertyId) const { - Property currentProperty = static_cast<Property>(propertyId); - switch (currentProperty) { - case Property::Rotate: - return mProperties.rotate; - case Property::PivotX: - return mProperties.pivotX; - case Property::PivotY: - return mProperties.pivotY; - case Property::ScaleX: - return mProperties.scaleX; - case Property::ScaleY: - return mProperties.scaleY; - case Property::TranslateX: - return mProperties.translateX; - case Property::TranslateY: - return mProperties.translateY; - default: - LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId); - return 0; + for (int i = 0; i < propertyCount; i++) { + Property currentProperty = static_cast<Property>(i); + switch (currentProperty) { + case Property::Rotate_Property: + outProperties[i] = mRotate; + break; + case Property::PivotX_Property: + outProperties[i] = mPivotX; + break; + case Property::PivotY_Property: + outProperties[i] = mPivotY; + break; + case Property::ScaleX_Property: + outProperties[i] = mScaleX; + break; + case Property::ScaleY_Property: + outProperties[i] = mScaleY; + break; + case Property::TranslateX_Property: + outProperties[i] = mTranslateX; + break; + case Property::TranslateY_Property: + outProperties[i] = mTranslateY; + break; + default: + LOG_ALWAYS_FATAL("Invalid input index: %d", i); + return false; + } } -} - -void Group::setPropertyValue(int propertyId, float value) { - Property currentProperty = static_cast<Property>(propertyId); - switch (currentProperty) { - case Property::Rotate: - mProperties.rotate = value; - break; - case Property::PivotX: - mProperties.pivotX = value; - break; - case Property::PivotY: - mProperties.pivotY = value; - break; - case Property::ScaleX: - mProperties.scaleX = value; - break; - case Property::ScaleY: - mProperties.scaleY = value; - break; - case Property::TranslateX: - mProperties.translateX = value; - break; - case Property::TranslateY: - mProperties.translateY = value; - break; - default: - LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId); - } -} - -bool Group::isValidProperty(int propertyId) { - return propertyId >= 0 && propertyId < static_cast<int>(Property::Count); + return true; } void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter, @@ -458,9 +445,7 @@ void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter, return; } - mPaint.setColorFilter(colorFilter); - - int saveCount = outCanvas->save(SkCanvas::SaveFlags::kMatrixClip_SaveFlag); + int saveCount = outCanvas->save(SaveFlags::MatrixClip); outCanvas->translate(mBounds.fLeft, mBounds.fTop); // Handle RTL mirroring. @@ -473,33 +458,43 @@ void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter, // And we use this bound for the destination rect for the drawBitmap, so // we offset to (0, 0); mBounds.offsetTo(0, 0); - createCachedBitmapIfNeeded(scaledWidth, scaledHeight); - outCanvas->drawVectorDrawable(this); + createCachedBitmapIfNeeded(scaledWidth, scaledHeight); + if (!mAllowCaching) { + updateCachedBitmap(scaledWidth, scaledHeight); + } else { + if (!canReuseCache || mCacheDirty) { + updateCachedBitmap(scaledWidth, scaledHeight); + } + } + drawCachedBitmapWithRootAlpha(outCanvas, colorFilter, mBounds); outCanvas->restoreToCount(saveCount); } -SkPaint* Tree::getPaint() { +void Tree::drawCachedBitmapWithRootAlpha(Canvas* outCanvas, SkColorFilter* filter, + const SkRect& originalBounds) { SkPaint* paint; - if (mRootAlpha == 1.0f && mPaint.getColorFilter() == NULL) { + if (mRootAlpha == 1.0f && filter == NULL) { paint = NULL; } else { mPaint.setFilterQuality(kLow_SkFilterQuality); mPaint.setAlpha(mRootAlpha * 255); + mPaint.setColorFilter(filter); paint = &mPaint; } - return paint; + outCanvas->drawBitmap(mCachedBitmap, 0, 0, mCachedBitmap.width(), mCachedBitmap.height(), + originalBounds.fLeft, originalBounds.fTop, originalBounds.fRight, + originalBounds.fBottom, paint); } -const SkBitmap& Tree::getBitmapUpdateIfDirty() { +void Tree::updateCachedBitmap(int width, int height) { mCachedBitmap.eraseColor(SK_ColorTRANSPARENT); SkCanvas outCanvas(mCachedBitmap); - float scaleX = (float) mCachedBitmap.width() / mViewportWidth; - float scaleY = (float) mCachedBitmap.height() / mViewportHeight; + float scaleX = width / mViewportWidth; + float scaleY = height / mViewportHeight; mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY); mCacheDirty = false; - return mCachedBitmap; } void Tree::createCachedBitmapIfNeeded(int width, int height) { diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h index f8f1ea62a624..09bdce596a21 100644 --- a/libs/hwui/VectorDrawable.h +++ b/libs/hwui/VectorDrawable.h @@ -18,7 +18,6 @@ #define ANDROID_HWUI_VPATH_H #include "Canvas.h" - #include <SkBitmap.h> #include <SkColor.h> #include <SkCanvas.h> @@ -105,21 +104,6 @@ protected: class ANDROID_API FullPath: public Path { public: - -struct Properties { - float strokeWidth = 0; - SkColor strokeColor = SK_ColorTRANSPARENT; - float strokeAlpha = 1; - SkColor fillColor = SK_ColorTRANSPARENT; - float fillAlpha = 1; - float trimPathStart = 0; - float trimPathEnd = 1; - float trimPathOffset = 0; - int32_t strokeLineCap = SkPaint::Cap::kButt_Cap; - int32_t strokeLineJoin = SkPaint::Join::kMiter_Join; - float strokeMiterLimit = 4; -}; - FullPath(const FullPath& path); // for cloning FullPath(const char* path, size_t strLength) : Path(path, strLength) {} FullPath() : Path() {} @@ -134,58 +118,55 @@ struct Properties { float strokeAlpha, SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin); - // TODO: Cleanup: Remove the setter and getters below, and their counterparts in java and JNI float getStrokeWidth() { - return mProperties.strokeWidth; + return mStrokeWidth; } void setStrokeWidth(float strokeWidth) { - mProperties.strokeWidth = strokeWidth; + mStrokeWidth = strokeWidth; } SkColor getStrokeColor() { - return mProperties.strokeColor; + return mStrokeColor; } void setStrokeColor(SkColor strokeColor) { - mProperties.strokeColor = strokeColor; + mStrokeColor = strokeColor; } float getStrokeAlpha() { - return mProperties.strokeAlpha; + return mStrokeAlpha; } void setStrokeAlpha(float strokeAlpha) { - mProperties.strokeAlpha = strokeAlpha; + mStrokeAlpha = strokeAlpha; } SkColor getFillColor() { - return mProperties.fillColor; + return mFillColor; } void setFillColor(SkColor fillColor) { - mProperties.fillColor = fillColor; + mFillColor = fillColor; } float getFillAlpha() { - return mProperties.fillAlpha; + return mFillAlpha; } void setFillAlpha(float fillAlpha) { - mProperties.fillAlpha = fillAlpha; + mFillAlpha = fillAlpha; } float getTrimPathStart() { - return mProperties.trimPathStart; + return mTrimPathStart; } void setTrimPathStart(float trimPathStart) { - VD_SET_PROP_WITH_FLAG(mProperties.trimPathStart, trimPathStart, mTrimDirty); + VD_SET_PROP_WITH_FLAG(mTrimPathStart, trimPathStart, mTrimDirty); } float getTrimPathEnd() { - return mProperties.trimPathEnd; + return mTrimPathEnd; } void setTrimPathEnd(float trimPathEnd) { - VD_SET_PROP_WITH_FLAG(mProperties.trimPathEnd, trimPathEnd, mTrimDirty); + VD_SET_PROP_WITH_FLAG(mTrimPathEnd, trimPathEnd, mTrimDirty); } float getTrimPathOffset() { - return mProperties.trimPathOffset; + return mTrimPathOffset; } void setTrimPathOffset(float trimPathOffset) { - VD_SET_PROP_WITH_FLAG(mProperties.trimPathOffset, trimPathOffset, mTrimDirty); + VD_SET_PROP_WITH_FLAG(mTrimPathOffset, trimPathOffset, mTrimDirty); } bool getProperties(int8_t* outProperties, int length); - void setColorPropertyValue(int propertyId, int32_t value); - void setPropertyValue(int propertyId, float value); void setFillGradient(SkShader* fillGradient) { SkRefCnt_SafeAssign(mFillGradient, fillGradient); @@ -201,28 +182,24 @@ protected: float strokeScale, const SkMatrix& matrix) override; private: - enum class Property { - StrokeWidth = 0, - StrokeColor, - StrokeAlpha, - FillColor, - FillAlpha, - TrimPathStart, - TrimPathEnd, - TrimPathOffset, - StrokeLineCap, - StrokeLineJoin, - StrokeMiterLimit, - Count, - }; // Applies trimming to the specified path. void applyTrim(); - Properties mProperties; + float mStrokeWidth = 0; + SkColor mStrokeColor = SK_ColorTRANSPARENT; + float mStrokeAlpha = 1; + SkColor mFillColor = SK_ColorTRANSPARENT; + SkShader* mStrokeGradient = nullptr; + SkShader* mFillGradient = nullptr; + float mFillAlpha = 1; + float mTrimPathStart = 0; + float mTrimPathEnd = 1; + float mTrimPathOffset = 0; bool mTrimDirty = true; + SkPaint::Cap mStrokeLineCap = SkPaint::Cap::kButt_Cap; + SkPaint::Join mStrokeLineJoin = SkPaint::Join::kMiter_Join; + float mStrokeMiterLimit = 4; SkPath mTrimmedSkPath; SkPaint mPaint; - SkShader* mStrokeGradient = nullptr; - SkShader* mFillGradient = nullptr; }; class ANDROID_API ClipPath: public Path { @@ -239,58 +216,49 @@ protected: class ANDROID_API Group: public Node { public: - struct Properties { - float rotate = 0; - float pivotX = 0; - float pivotY = 0; - float scaleX = 1; - float scaleY = 1; - float translateX = 0; - float translateY = 0; - }; Group(const Group& group); Group() {} float getRotation() { - return mProperties.rotate; + return mRotate; } void setRotation(float rotation) { - mProperties.rotate = rotation; + mRotate = rotation; } float getPivotX() { - return mProperties.pivotX; + return mPivotX; } void setPivotX(float pivotX) { - mProperties.pivotX = pivotX; + mPivotX = pivotX; } float getPivotY() { - return mProperties.pivotY; + return mPivotY; } void setPivotY(float pivotY) { - mProperties.pivotY = pivotY; + mPivotY = pivotY; } float getScaleX() { - return mProperties.scaleX; + return mScaleX; } void setScaleX(float scaleX) { - mProperties.scaleX = scaleX; + mScaleX = scaleX; } float getScaleY() { - return mProperties.scaleY; + return mScaleY; } void setScaleY(float scaleY) { - mProperties.scaleY = scaleY; + mScaleY = scaleY; } float getTranslateX() { - return mProperties.translateX; + return mTranslateX; } void setTranslateX(float translateX) { - mProperties.translateX = translateX; + mTranslateX = translateX; } float getTranslateY() { - return mProperties.translateY; + return mTranslateY; } void setTranslateY(float translateY) { - mProperties.translateY = translateY; + mTranslateY = translateY; } virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, float scaleX, float scaleY) override; @@ -300,33 +268,38 @@ public: void addChild(Node* child); void dump() override; bool getProperties(float* outProperties, int length); - float getPropertyValue(int propertyId) const; - void setPropertyValue(int propertyId, float value); - static bool isValidProperty(int propertyId); private: enum class Property { - Rotate = 0, - PivotX, - PivotY, - ScaleX, - ScaleY, - TranslateX, - TranslateY, + Rotate_Property = 0, + PivotX_Property, + PivotY_Property, + ScaleX_Property, + ScaleY_Property, + TranslateX_Property, + TranslateY_Property, // Count of the properties, must be at the end. Count, }; + float mRotate = 0; + float mPivotX = 0; + float mPivotY = 0; + float mScaleX = 1; + float mScaleY = 1; + float mTranslateX = 0; + float mTranslateY = 0; std::vector<Node*> mChildren; - Properties mProperties; }; -class ANDROID_API Tree : public VirtualLightRefBase { +class ANDROID_API Tree { public: Tree(Group* rootNode) : mRootNode(rootNode) {} void draw(Canvas* outCanvas, SkColorFilter* colorFilter, const SkRect& bounds, bool needsMirroring, bool canReuseCache); + void drawCachedBitmapWithRootAlpha(Canvas* outCanvas, SkColorFilter* filter, + const SkRect& originalBounds); - const SkBitmap& getBitmapUpdateIfDirty(); + void updateCachedBitmap(int width, int height); void createCachedBitmapIfNeeded(int width, int height); bool canReuseBitmap(int width, int height); void setAllowCaching(bool allowCaching) { @@ -343,10 +316,6 @@ public: mViewportWidth = viewportWidth; mViewportHeight = viewportHeight; } - SkPaint* getPaint(); - const SkRect& getBounds() const { - return mBounds; - } private: // Cap the bitmap size, such that it won't hurt the performance too much diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index d4116218e5e1..ea702c01694e 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -92,18 +92,18 @@ void CanvasContext::destroy() { } } -void CanvasContext::setSurface(ANativeWindow* window) { +void CanvasContext::setSurface(Surface* surface) { ATRACE_CALL(); - mNativeWindow = window; + mNativeSurface = surface; if (mEglSurface != EGL_NO_SURFACE) { mEglManager.destroySurface(mEglSurface); mEglSurface = EGL_NO_SURFACE; } - if (window) { - mEglSurface = mEglManager.createSurface(window); + if (surface) { + mEglSurface = mEglManager.createSurface(surface); } if (mEglSurface != EGL_NO_SURFACE) { @@ -127,8 +127,8 @@ void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) { mSwapBehavior = swapBehavior; } -void CanvasContext::initialize(ANativeWindow* window) { - setSurface(window); +void CanvasContext::initialize(Surface* surface) { + setSurface(surface); #if !HWUI_NEW_OPS if (mCanvas) return; mCanvas = new OpenGLRenderer(mRenderThread.renderState()); @@ -136,11 +136,11 @@ void CanvasContext::initialize(ANativeWindow* window) { #endif } -void CanvasContext::updateSurface(ANativeWindow* window) { - setSurface(window); +void CanvasContext::updateSurface(Surface* surface) { + setSurface(surface); } -bool CanvasContext::pauseSurface(ANativeWindow* window) { +bool CanvasContext::pauseSurface(Surface* surface) { return mRenderThread.removeFrameCallback(this); } @@ -204,6 +204,10 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, info.renderer = mCanvas; #endif + if (CC_LIKELY(mNativeSurface.get())) { + info.frameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber()); + } + mAnimationContext->startFrame(info.mode); for (const sp<RenderNode>& node : mRenderNodes) { // Only the primary target node will be drawn full - all other nodes would get drawn in @@ -219,7 +223,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, freePrefetechedLayers(); GL_CHECKPOINT(MODERATE); - if (CC_UNLIKELY(!mNativeWindow.get())) { + if (CC_UNLIKELY(!mNativeSurface.get())) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); info.out.canDrawThisFrame = false; return; @@ -242,8 +246,9 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, } else { // We're maybe behind? Find out for sure int runningBehind = 0; - mNativeWindow->query(mNativeWindow.get(), - NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind); + // TODO: Have this method be on Surface, too, not just ANativeWindow... + ANativeWindow* window = mNativeSurface.get(); + window->query(window, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind); info.out.canDrawThisFrame = !runningBehind; } } else { diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 63a7977f0cc9..168166ef5b23 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -39,6 +39,7 @@ #include <SkBitmap.h> #include <SkRect.h> #include <utils/Functor.h> +#include <gui/Surface.h> #include <set> #include <string> @@ -75,10 +76,10 @@ public: // Won't take effect until next EGLSurface creation void setSwapBehavior(SwapBehavior swapBehavior); - void initialize(ANativeWindow* window); - void updateSurface(ANativeWindow* window); - bool pauseSurface(ANativeWindow* window); - bool hasSurface() { return mNativeWindow.get(); } + void initialize(Surface* surface); + void updateSurface(Surface* surface); + bool pauseSurface(Surface* surface); + bool hasSurface() { return mNativeSurface.get(); } void setup(int width, int height, float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); @@ -172,7 +173,7 @@ private: // lifecycle tracking friend class android::uirenderer::RenderState; - void setSurface(ANativeWindow* window); + void setSurface(Surface* window); void requireSurface(); void freePrefetechedLayers(); @@ -182,7 +183,7 @@ private: RenderThread& mRenderThread; EglManager& mEglManager; - sp<ANativeWindow> mNativeWindow; + sp<Surface> mNativeSurface; EGLSurface mEglSurface = EGL_NO_SURFACE; bool mBufferPreserved = false; SwapBehavior mSwapBehavior = kSwap_default; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 1d1b144bd47e..7c6cd7e014ef 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -139,38 +139,38 @@ void RenderProxy::setName(const char* name) { postAndWait(task); // block since name/value pointers owned by caller } -CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) { - args->context->initialize(args->window); +CREATE_BRIDGE2(initialize, CanvasContext* context, Surface* surface) { + args->context->initialize(args->surface); return nullptr; } -void RenderProxy::initialize(const sp<ANativeWindow>& window) { +void RenderProxy::initialize(const sp<Surface>& surface) { SETUP_TASK(initialize); args->context = mContext; - args->window = window.get(); + args->surface = surface.get(); post(task); } -CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) { - args->context->updateSurface(args->window); +CREATE_BRIDGE2(updateSurface, CanvasContext* context, Surface* surface) { + args->context->updateSurface(args->surface); return nullptr; } -void RenderProxy::updateSurface(const sp<ANativeWindow>& window) { +void RenderProxy::updateSurface(const sp<Surface>& surface) { SETUP_TASK(updateSurface); args->context = mContext; - args->window = window.get(); + args->surface = surface.get(); postAndWait(task); } -CREATE_BRIDGE2(pauseSurface, CanvasContext* context, ANativeWindow* window) { - return (void*) args->context->pauseSurface(args->window); +CREATE_BRIDGE2(pauseSurface, CanvasContext* context, Surface* surface) { + return (void*) args->context->pauseSurface(args->surface); } -bool RenderProxy::pauseSurface(const sp<ANativeWindow>& window) { +bool RenderProxy::pauseSurface(const sp<Surface>& surface) { SETUP_TASK(pauseSurface); args->context = mContext; - args->window = window.get(); + args->surface = surface.get(); return (bool) postAndWait(task); } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 4180d8020179..178724a85d04 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -67,9 +67,9 @@ public: ANDROID_API bool loadSystemProperties(); ANDROID_API void setName(const char* name); - ANDROID_API void initialize(const sp<ANativeWindow>& window); - ANDROID_API void updateSurface(const sp<ANativeWindow>& window); - ANDROID_API bool pauseSurface(const sp<ANativeWindow>& window); + ANDROID_API void initialize(const sp<Surface>& surface); + ANDROID_API void updateSurface(const sp<Surface>& surface); + ANDROID_API bool pauseSurface(const sp<Surface>& surface); ANDROID_API void setup(int width, int height, float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); ANDROID_API void setLightCenter(const Vector3& lightCenter); diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp index a843e9265ef1..58c0876cb4cb 100644 --- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp +++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp @@ -112,9 +112,9 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) { scene->doFrame(i); proxy->syncAndDrawFrame(); } - proxy->fence(); - nsecs_t done = systemTime(CLOCK_MONOTONIC); if (opts.reportFrametimeWeight) { + proxy->fence(); + nsecs_t done = systemTime(CLOCK_MONOTONIC); avgMs.add((done - vsync) / 1000000.0); if (i % 10 == 9) { printf("Average frametime %.3fms\n", avgMs.average()); diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp index 83af148d095e..b317c1292623 100644 --- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp +++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp @@ -63,7 +63,7 @@ void BM_DisplayListCanvas_record_empty::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; ++i) { - canvas.reset(100, 100); + canvas.resetRecording(100, 100); MicroBench::DoNotOptimize(&canvas); delete canvas.finishRecording(); } @@ -77,7 +77,7 @@ void BM_DisplayListCanvas_record_saverestore::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; ++i) { - canvas.reset(100, 100); + canvas.resetRecording(100, 100); canvas.save(SaveFlags::MatrixClip); canvas.save(SaveFlags::MatrixClip); MicroBench::DoNotOptimize(&canvas); @@ -95,7 +95,7 @@ void BM_DisplayListCanvas_record_translate::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; ++i) { - canvas.reset(100, 100); + canvas.resetRecording(100, 100); canvas.scale(10, 10); MicroBench::DoNotOptimize(&canvas); delete canvas.finishRecording(); @@ -119,7 +119,7 @@ void BM_DisplayListCanvas_record_simpleBitmapView::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; ++i) { - canvas.reset(100, 100); + canvas.resetRecording(100, 100); { canvas.save(SaveFlags::MatrixClip); canvas.drawRect(0, 0, 100, 100, rectPaint); diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp index 01bfc5adbbbd..20d2f1f18c58 100644 --- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp +++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp @@ -455,6 +455,23 @@ TEST(RecordingCanvas, drawRenderNode_projection) { } } +TEST(RecordingCanvas, firstClipWillReplace) { + auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { + canvas.save(SaveFlags::MatrixClip); + // since no explicit clip set on canvas, this should be the one observed on op: + canvas.clipRect(-100, -100, 300, 300, SkRegion::kIntersect_Op); + + SkPaint paint; + paint.setColor(SK_ColorWHITE); + canvas.drawRect(0, 0, 100, 100, paint); + + canvas.restore(); + }); + ASSERT_EQ(1u, dl->getOps().size()) << "Must have one op"; + // first clip must be preserved, even if it extends beyond canvas bounds + EXPECT_CLIP_RECT(Rect(-100, -100, 300, 300), dl->getOps()[0]->localClip); +} + TEST(RecordingCanvas, insertReorderBarrier) { auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { canvas.drawRect(0, 0, 400, 400, SkPaint()); diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp new file mode 100644 index 000000000000..586625bf97cf --- /dev/null +++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#include "tests/common/TestUtils.h" + +#include <gtest/gtest.h> +#include <SkShader.h> + +using namespace android; +using namespace android::uirenderer; + +/** + * 1x1 bitmaps must not be optimized into solid color shaders, since HWUI can't + * compose/render color shaders + */ +TEST(SkiaBehavior, CreateBitmapShader1x1) { + SkBitmap origBitmap = TestUtils::createSkBitmap(1, 1); + std::unique_ptr<SkShader> s(SkShader::CreateBitmapShader( + origBitmap, + SkShader::kClamp_TileMode, + SkShader::kRepeat_TileMode)); + + SkBitmap bitmap; + SkShader::TileMode xy[2]; + ASSERT_TRUE(s->isABitmap(&bitmap, nullptr, xy)) + << "1x1 bitmap shader must query as bitmap shader"; + EXPECT_EQ(SkShader::kClamp_TileMode, xy[0]); + EXPECT_EQ(SkShader::kRepeat_TileMode, xy[1]); + EXPECT_EQ(origBitmap.pixelRef(), bitmap.pixelRef()); +} diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 3007d86afebc..b26b310a904b 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -1784,9 +1784,9 @@ public class AudioTrack implements AudioRouting * Note that the actual playback of this data might occur after this function returns. * * @param audioData the array that holds the data to play. - * @param offsetInBytes the offset expressed in bytes in audioData where the data to play + * @param offsetInBytes the offset expressed in bytes in audioData where the data to write * starts. - * @param sizeInBytes the number of bytes to read in audioData after the offset. + * @param sizeInBytes the number of bytes to write in audioData after the offset. * @return zero or the positive number of bytes that were written, or * {@link #ERROR_INVALID_OPERATION} * if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if @@ -1821,9 +1821,9 @@ public class AudioTrack implements AudioRouting * Note that the actual playback of this data might occur after this function returns. * * @param audioData the array that holds the data to play. - * @param offsetInBytes the offset expressed in bytes in audioData where the data to play + * @param offsetInBytes the offset expressed in bytes in audioData where the data to write * starts. - * @param sizeInBytes the number of bytes to read in audioData after the offset. + * @param sizeInBytes the number of bytes to write in audioData after the offset. * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no * effect in static mode. * <br>With {@link #WRITE_BLOCKING}, the write will block until all data has been written @@ -1920,8 +1920,8 @@ public class AudioTrack implements AudioRouting * In static buffer mode, copies the data to the buffer starting at offset 0. * Note that the actual playback of this data might occur after this function returns. * - * @param audioData the array that holds the data to play. - * @param offsetInShorts the offset expressed in shorts in audioData where the data to play + * @param audioData the array that holds the data to write. + * @param offsetInShorts the offset expressed in shorts in audioData where the data to write * starts. * @param sizeInShorts the number of shorts to read in audioData after the offset. * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no @@ -1987,7 +1987,7 @@ public class AudioTrack implements AudioRouting * and the write mode is ignored. * Note that the actual playback of this data might occur after this function returns. * - * @param audioData the array that holds the data to play. + * @param audioData the array that holds the data to write. * The implementation does not clip for sample values within the nominal range * [-1.0f, 1.0f], provided that all gains in the audio pipeline are * less than or equal to unity (1.0f), and in the absence of post-processing effects @@ -1998,8 +1998,8 @@ public class AudioTrack implements AudioRouting * and later processing in the audio path. Therefore applications are encouraged * to provide samples values within the nominal range. * @param offsetInFloats the offset, expressed as a number of floats, - * in audioData where the data to play starts. - * @param sizeInFloats the number of floats to read in audioData after the offset. + * in audioData where the data to write starts. + * @param sizeInFloats the number of floats to write in audioData after the offset. * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no * effect in static mode. * <br>With {@link #WRITE_BLOCKING}, the write will block until all data has been written @@ -2070,7 +2070,7 @@ public class AudioTrack implements AudioRouting * and the write mode is ignored. * Note that the actual playback of this data might occur after this function returns. * - * @param audioData the buffer that holds the data to play, starting at the position reported + * @param audioData the buffer that holds the data to write, starting at the position reported * by <code>audioData.position()</code>. * <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will * have been advanced to reflect the amount of data that was successfully written to @@ -2137,7 +2137,7 @@ public class AudioTrack implements AudioRouting /** * Writes the audio data to the audio sink for playback in streaming mode on a HW_AV_SYNC track. * The blocking behavior will depend on the write mode. - * @param audioData the buffer that holds the data to play, starting at the position reported + * @param audioData the buffer that holds the data to write, starting at the position reported * by <code>audioData.position()</code>. * <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will * have been advanced to reflect the amount of data that was successfully written to diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java index 80b3ffc23e31..56b25144d948 100644 --- a/media/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java @@ -117,6 +117,9 @@ public final class MediaBrowser { * to the media browse service when connecting and retrieving the root id * for browsing, or null if none. The contents of this bundle may affect * the information returned when browsing. + * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_RECENT + * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_OFFLINE + * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED */ public MediaBrowser(Context context, ComponentName serviceComponent, ConnectionCallback callback, Bundle rootHints) { diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 20491e4baa70..f9a23f9cab04 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -32,6 +32,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.hardware.hdmi.HdmiDeviceInfo; import android.net.Uri; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; @@ -114,6 +115,7 @@ public final class TvInputInfo implements Parcelable { private final int mTunerCount; private final boolean mCanRecord; private final boolean mIsHardwareInput; + private final Bundle mExtras; // Attributes from XML meta data. private String mSetupActivity; @@ -252,7 +254,7 @@ public final class TvInputInfo implements Parcelable { */ private TvInputInfo(ResolveInfo service, String id, String parentId, int type, boolean isHardwareInput, boolean isConnectedToHdmiSwitch, int tunerCount, - boolean canRecord) { + boolean canRecord, Bundle extras) { mService = service; mId = id; mParentId = parentId; @@ -261,6 +263,7 @@ public final class TvInputInfo implements Parcelable { mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch; mTunerCount = tunerCount; mCanRecord = canRecord; + mExtras = extras; } /** @@ -362,6 +365,14 @@ public final class TvInputInfo implements Parcelable { } /** + * Returns the extras associated with this TV input. + * @hide + */ + public Bundle getExtras() { + return mExtras; + } + + /** * Returns the HDMI device information of this TV input. * @hide */ @@ -524,6 +535,7 @@ public final class TvInputInfo implements Parcelable { dest.writeInt(mLabelResId); dest.writeString(mLabel); dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0); + dest.writeBundle(mExtras); } private Drawable loadServiceIcon(Context context) { @@ -563,6 +575,7 @@ public final class TvInputInfo implements Parcelable { mLabelResId = in.readInt(); mLabel = in.readString(); mIsConnectedToHdmiSwitch = in.readByte() == 1; + mExtras = in.readBundle(); } /** @@ -604,6 +617,7 @@ public final class TvInputInfo implements Parcelable { private HdmiDeviceInfo mHdmiDeviceInfo; private String mParentId; private TvInputHardwareInfo mTvInputHardwareInfo; + private Bundle mExtras; /** * Constructs a new builder for {@link TvInputInfo}. @@ -732,6 +746,18 @@ public final class TvInputInfo implements Parcelable { } /** + * Sets the extras associated with this TV input. + * + * @param extras The extras associated with this TV input. + * @return This Builder object to allow for chaining of calls to builder methods. + * @hide + */ + public Builder setExtras(Bundle extras) { + this.mExtras = extras; + return this; + } + + /** * Creates a {@link TvInputInfo} instance with the specified fields. Most of the information * is obtained by parsing the AndroidManifest and {@link TvInputService#SERVICE_META_DATA} * for the {@link TvInputService} this TV input implements. @@ -765,7 +791,7 @@ public final class TvInputInfo implements Parcelable { } TvInputInfo info = new TvInputInfo(mResolveInfo, id, mParentId, type, isHardwareInput, - isConnectedToHdmiSwitch, mTunerCount, mCanRecord); + isConnectedToHdmiSwitch, mTunerCount, mCanRecord, mExtras); return parseServiceMetadata(type, info); } diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index 0393c943784d..3372524d138c 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -351,6 +351,9 @@ public abstract class MediaBrowserService extends Service { * root id for browsing, or null if none. The contents of this * bundle may affect the information returned when browsing. * @return The {@link BrowserRoot} for accessing this app's content or null. + * @see BrowserRoot#EXTRA_RECENT + * @see BrowserRoot#EXTRA_OFFLINE + * @see BrowserRoot#EXTRA_SUGGESTED */ public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints); @@ -667,6 +670,57 @@ public abstract class MediaBrowserService extends Service { * when first connected. */ public static final class BrowserRoot { + /** + * The lookup key for a boolean that indicates whether the browser service should return a + * browser root for recently played media items. + * + * <p>When creating a media browser for a given media browser service, this key can be + * supplied as a root hint for retrieving media items that are recently played. + * If the media browser service can provide such media items, the implementation must return + * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back. + * + * <p>The root hint may contain multiple keys. + * + * @see #EXTRA_OFFLINE + * @see #EXTRA_SUGGESTED + */ + public static final String EXTRA_RECENT = "android.service.media.extra.RECENT"; + + /** + * The lookup key for a boolean that indicates whether the browser service should return a + * browser root for offline media items. + * + * <p>When creating a media browser for a given media browser service, this key can be + * supplied as a root hint for retrieving media items that are can be played without an + * internet connection. + * If the media browser service can provide such media items, the implementation must return + * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back. + * + * <p>The root hint may contain multiple keys. + * + * @see #EXTRA_RECENT + * @see #EXTRA_SUGGESTED + */ + public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE"; + + /** + * The lookup key for a boolean that indicates whether the browser service should return a + * browser root for suggested media items. + * + * <p>When creating a media browser for a given media browser service, this key can be + * supplied as a root hint for retrieving the media items suggested by the media browser + * service. The list of media items passed in {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)} + * is considered ordered by relevance, first being the top suggestion. + * If the media browser service can provide such media items, the implementation must return + * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back. + * + * <p>The root hint may contain multiple keys. + * + * @see #EXTRA_RECENT + * @see #EXTRA_OFFLINE + */ + public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED"; + final private String mRootId; final private Bundle mExtras; diff --git a/packages/DocumentsUI/lint.xml b/packages/DocumentsUI/lint.xml index 70d1ddff4074..09661bab67fc 100644 --- a/packages/DocumentsUI/lint.xml +++ b/packages/DocumentsUI/lint.xml @@ -1,8 +1,36 @@ <?xml version="1.0" encoding="UTF-8"?> <lint> - <!-- min-sdk doesn't apply to platform apps --> + <!-- + Lint configuration for the framework-lint tool (go/fwlint). See + http://tools.android.com/tips/lint for full docs on the lint tool. + --> + + <!-- min-sdk doesn't apply to platform apps. --> <issue id="UsesMinSdkAttributes" severity="ignore" /> - <!-- Protected permissions don't apply to system apps --> + <!-- Protected permissions don't apply to system apps. --> <issue id="ProtectedPermissions" severity="ignore" /> + + <!-- Other recommended suppressions copied from go/fwlint. --> + <issue id="Assert" severity="ignore" /> + <issue id="ClickableViewAccessibility" severity="ignore" /> + <issue id="GoogleAppIndexingWarning" severity="ignore" /> + <issue id="MissingPermission" severity="ignore" /> + <issue id="ParcelClassLoader" severity="ignore" /> + <issue id="ParcelCreator" severity="ignore" /> + <issue id="Registered" severity="ignore" /> + <issue id="RtlHardcoded" severity="ignore" /> + <issue id="ShiftFlags" severity="ignore" /> + <issue id="SuspiciousImport" severity="ignore" /> + + <!-- Don't lint automatically translated strings. --> + <issue id="all"> + <ignore path="res/values-*/strings.xml" /> + </issue> + + <!-- Don't warn about missing translations. --> + <issue id="MissingTranslation"> + <ignore path="res/values/strings.xml" /> + </issue> + </lint> diff --git a/packages/DocumentsUI/res/drawable/cabinet.png b/packages/DocumentsUI/res/drawable/cabinet.png Binary files differdeleted file mode 100644 index da440239cd0f..000000000000 --- a/packages/DocumentsUI/res/drawable/cabinet.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable/cabinet.xml b/packages/DocumentsUI/res/drawable/cabinet.xml new file mode 100644 index 000000000000..843ffc74e593 --- /dev/null +++ b/packages/DocumentsUI/res/drawable/cabinet.xml @@ -0,0 +1,81 @@ +<!-- +Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="672dp" + android:height="921dp" + android:viewportWidth="672.0" + android:viewportHeight="921.0"> + <path + android:pathData="M286,0c5,0,10,0,15,0c0.1,1.8,1.5,1.8,2.8,2.1c11.1,2,22.1,4,33.2,6.1c31.8,6.1,63.7,12.3,95.5,18.5 c16.1,3.1,32.1,6.2,48.2,9.3c26,4.9,52.1,9.3,78,14.6c10.8,2.2,21.6,4.6,32.3,6.5c11.3,2,22.6,4.7,34,6c7.9,0.9,7.9,1.1,7.9,9.2 c0,237.3,0,474.5,0,711.8c-1.5,0.9,-3,2,-4.6,2.8c-18.3,8.3,-36.6,16.6,-54.8,25c-29.3,13.4,-58.5,26.8,-87.8,40.3 c-23.5,10.9,-47,21.8,-70.4,32.8c-2.1,1,-4.2,1.5,-6.3,1.1c-6.8,-1.3,-13.6,-2.5,-20.1,-4.9c5.9,-0.3,11.4,1.9,17.1,2.9c5.9,1.1,5.9,1,5.9,-4.9 c0,-17.1,0.1,-34.3,0,-51.4c-0.3,-68.9,-0.7,-137.8,-1,-206.7c0,-35.8,0,-71.6,0.1,-107.4c0,-3.8,-0.6,-5.2,-4.7,-3.7c-7.9,2.9,-16,5.4,-24.1,7.8 c-14.1,4.3,-27.8,10,-42.2,13.2c0,-64,0,-127.9,-0.1,-191.9c0,-4.1,1.3,-5.9,5.1,-7c21,-6.6,42,-13.4,63,-20.2c2.3,-0.8,4.4,-1.8,4,-4.9 c0,-59.3,0,-118.7,0,-178c0,-1.3,-0.7,-2,-2,-2c-2.6,-0.4,-5.2,-0.7,-7.8,-1.2c-30.2,-5.3,-60.5,-10.6,-90.7,-16c-31.9,-5.6,-63.7,-11.3,-95.6,-16.9 c-24.9,-4.4,-49.8,-8.7,-74.6,-13.1C117.1,75.6,93.1,71.3,69,67c-0.3,-0.3,-0.7,-0.7,-1,-1c17.4,-5.3,34.8,-10.7,52.3,-15.9 c29.4,-8.7,58.8,-17.2,88.2,-25.8c24.3,-7.1,48.6,-14.2,72.9,-21.4C283.1,2.4,285.6,2.7,286,0z" + android:fillColor="#EFEFEE"/> + <path + android:pathData="M412,307c0.4,3,-1.7,4.1,-4,4.9c-21,6.8,-42,13.6,-63,20.2c-3.8,1.2,-5.1,3,-5.1,7C340,403.1,340,467,340,531 c-11.8,-1.2,-23.3,-4.5,-34.9,-6.5c-10,-1.7,-19.9,-4.6,-30.1,-5.5c-0.7,-0.3,-1.4,-0.9,-2.2,-1c-19.8,-4,-39.5,-8,-59.3,-12c-12.2,-2.4,-24.3,-4.7,-36.5,-7 c-0.9,-0.3,-1.8,-0.8,-2.8,-1c-24.5,-4.9,-48.9,-9.9,-73.5,-14.6C89.3,481.3,78,477.1,66,478c-0.7,-1.6,-2.1,-1.8,-3.6,-2.1 c-11.1,-2.2,-22.2,-4.7,-33.3,-6.7c-9.7,-1.7,-19.1,-4.9,-29.1,-5.3c0,-64.3,0,-128.7,0,-193c0.8,-0.2,1.6,-0.4,2.4,-0.7c19,-7.8,37.9,-15.9,57.1,-23.4 c5.4,-2.1,6.7,-4.8,6.6,-10.2c-0.2,-55.1,-0.1,-110.2,-0.1,-165.4c0,-1.9,-1.4,-4.6,1.9,-5.4c0.3,0.3,0.7,0.7,1,1c-1.3,4.9,-1,9.9,-1,14.9 c0,51.1,0,102.3,0,153.4c0,1.2,0,2.3,0,3.5c0.1,3.5,1.2,5.9,5.3,6.5c7,1.1,14,2.6,21,3.9c22.1,4.3,44.1,8.6,66.2,12.8 c27.3,5.2,54.6,10.1,81.9,15.3c21.8,4.1,43.5,8.5,65.2,12.6c28.1,5.4,56.2,10.8,84.3,15.8C398.4,306.8,405.1,310.5,412,307z M105,329c0,3.3,0,6.7,-0.1,10c-0.1,2.5,0.4,3.6,3.4,4.2c30,5.3,59.9,10.9,89.8,16.5c3.4,0.6,5.1,0.2,4.9,-3.7 c-0.2,-3.3,-0.1,-6.7,-0.1,-10c0.5,-3.6,-0.1,-6.3,-4.7,-6.1c-1.1,0.1,-2.2,-0.6,-3.4,-0.8c-28.3,-5,-56.6,-9.9,-84.9,-14.9 C105.6,323.4,104.5,325.2,105,329z M65.9,280.8c13.7,2.5,27.4,4.9,41.1,7.4c32.6,5.9,65.2,11.8,97.8,17.8 c41.4,7.6,82.8,15.2,124.2,22.8c6.8,1.2,13.3,1.4,20,-1.3c9.3,-3.6,18.9,-6.3,28.4,-9.4c6.4,-2.1,12.8,-4.2,19.2,-6.4 c-4.2,-2,-8.3,-3,-12.4,-3.8c-22.6,-4.2,-45.3,-8,-67.9,-12.6c-14.6,-3,-29.2,-5.6,-43.8,-8.5c-24,-4.6,-48,-9.2,-72,-13.7c-15.9,-3,-31.8,-6.2,-47.8,-9.2 c-19,-3.6,-38,-7.3,-57,-10.6c-9.9,-1.7,-19.6,-4.5,-29.7,-5.2C48,255.6,30.1,263,12.2,270.4c0,0.4,0,0.7,0,1.1 C30.1,274.6,48,277.7,65.9,280.8z" + android:fillColor="#EAEAEA"/> + <path + android:pathData="M672,782c-6,0.9,-11.1,4.3,-16.4,6.9c-30.8,15,-61.5,30.3,-92.3,45.4c-34.8,17.1,-69.5,34.3,-104.5,51.1 c-13,6.3,-26,12.8,-39,19.1c-1.5,0.7,-3.7,1,-3.9,3.4c-3.7,0,-7.3,0,-11,0c-0.4,-3,-3.1,-2.3,-4.7,-2.7c-19.3,-4.8,-38.6,-9.5,-57.9,-14.1 c-27.5,-6.5,-55.2,-12.7,-82.6,-19.4c-30.9,-7.5,-61.8,-15,-92.7,-22.1c-24.8,-5.8,-49.5,-12,-74.3,-18C70.8,826.5,48.9,821.3,27,816 c-1.1,-0.3,-2.3,-0.5,-3.3,-1c-3.2,-1.3,-3.5,-3.3,-0.7,-5.4c0.9,-0.7,2,-1.2,3.1,-1.7c12,-5.3,24,-10.7,36,-16c0.4,-0.2,0.9,-0.2,1.9,-0.3 c0,3.6,0,7,0,10.5c0,1.6,-0.5,3.5,2,3.9c0.7,2.8,3.2,2.5,5.2,3c39.3,9,78.7,18.1,118.1,27c43.9,10,87.7,20,131.6,29.9 c9.7,2.2,19.2,4.9,29.1,6c1.1,1.5,2.6,0.9,4,1l0,0c4.1,2,8.5,2.6,13,3l0,0c7.2,2.4,14.4,4.3,22,5l0,0c6.5,2.5,13.3,3.6,20.1,4.9 c2.1,0.4,4.2,-0.1,6.3,-1.1c23.5,-11,46.9,-21.9,70.4,-32.8c29.2,-13.5,58.5,-26.9,87.8,-40.3c18.3,-8.4,36.6,-16.6,54.8,-25 c1.6,-0.7,3.1,-1.9,4.6,-2.8c2,-2.9,1.1,-6.2,0.9,-9.2c-0.3,-4.7,1.9,-5.5,5.7,-4.7c10.8,2.2,21.6,4.6,32.5,6.9C672,778.7,672,780.3,672,782z " + android:fillColor="#E6E4E4"/> + <path + android:pathData="M350,872c-9.9,-1.1,-19.4,-3.9,-29.1,-6C277,856,233.1,846,189.2,836c-39.4,-9,-78.7,-18,-118.1,-27 c-2,-0.4,-4.5,-0.2,-5.2,-3c0,-85.7,0,-171.4,0.1,-257.1c6.5,0.1,12.7,2.3,19,3.6c26.4,5.4,52.8,10.9,79.2,16.5c25.9,5.4,51.8,11,77.7,16.4 c26.2,5.5,52.5,11,78.7,16.5c30.1,6.3,60.2,12.6,90.3,19c0.3,68.9,0.7,137.8,1,206.7c0.1,17.1,0,34.3,0,51.4c0,5.9,0,6,-5.9,4.9 c-5.7,-1.1,-11.2,-3.2,-17.1,-2.9c0,0,0,0,0,0c-7,-3.1,-14.2,-5.4,-22,-5c0,0,0,0,0,0c-3.9,-2.9,-8.4,-2.9,-13,-3c0,0,0,0,0,0 C352.9,871.5,351.4,872.1,350,872z M177,687c0,3.2,0.1,6.3,0,9.5c-0.1,2.7,0.7,4,3.8,4.6c29.7,5.8,59.3,11.7,89,17.7 c2.4,0.5,4.7,0.1,4.9,-2.6c0.4,-3.7,1.2,-7.6,-0.6,-11.2c1,-3,1.2,-5.3,-3,-6c-29.6,-5.4,-59.2,-10.8,-88.7,-16.5C177.7,681.6,176.5,682.8,177,687 z" + android:fillColor="#E5E5E5"/> + <path + android:pathData="M411,621c-30.1,-6.3,-60.2,-12.6,-90.3,-19c-26.2,-5.5,-52.5,-11,-78.7,-16.5c-25.9,-5.5,-51.8,-11,-77.7,-16.4 c-26.4,-5.5,-52.8,-11.1,-79.2,-16.5c-6.3,-1.3,-12.5,-3.5,-19,-3.6c0,-23.6,0,-47.3,0,-70.9c12,-0.9,23.2,3.3,34.7,5.5c24.5,4.6,49,9.7,73.5,14.6 c1,0.2,1.9,0.6,2.8,1c0,3.3,0.7,6.7,0.7,9.9c0,5.6,2.4,7.5,7.5,8.4c15.3,2.7,30.5,5.8,45.8,8.7c12,2.3,24,4.4,36.1,6.6 c1.9,0.3,4.8,1.5,4.7,-1.4c-0.2,-4.6,1.7,-8.2,3.3,-12.1c10.2,0.9,20,3.8,30.1,5.5c11.7,2,23.1,5.3,34.9,6.5 c14.5,-3.2,28.1,-8.9,42.2,-13.2c8.1,-2.5,16.2,-5,24.1,-7.8c4.1,-1.5,4.8,-0.1,4.7,3.7C411,549.4,411,585.2,411,621z" + android:fillColor="#D9D9D9"/> + <path + android:pathData="M412,307c-6.9,3.5,-13.6,-0.2,-20.1,-1.3c-28.2,-5,-56.2,-10.4,-84.3,-15.8c-21.8,-4.1,-43.5,-8.5,-65.2,-12.6 c-27.3,-5.2,-54.6,-10.1,-81.9,-15.3c-22.1,-4.2,-44.1,-8.5,-66.2,-12.8c-7,-1.3,-13.9,-2.9,-21,-3.9c-4.1,-0.6,-5.2,-3,-5.3,-6.5c0,-1.2,0,-2.3,0,-3.5 c0,-51.1,0,-102.3,0,-153.4c0,-5,-0.3,-10,1,-14.9c24.1,4.3,48.1,8.6,72.2,12.8c24.9,4.4,49.8,8.7,74.6,13.1c31.9,5.6,63.7,11.3,95.6,16.9 c30.2,5.3,60.5,10.6,90.7,16c2.6,0.5,5.2,0.8,7.8,1.2c0,1.3,0.7,2,2,2C412,188.3,412,247.7,412,307z M409,217.4c0,-25.5,0,-51,0,-76.5 c0,-10.9,0.1,-11.2,-10.7,-13.2c-23.4,-4.4,-46.8,-8.5,-70.3,-12.6c-24.1,-4.3,-48.2,-8.4,-72.3,-12.6c-17.7,-3.1,-35.5,-6.3,-53.2,-9.4 c-22.1,-3.9,-44.3,-7.6,-66.4,-11.5c-20,-3.5,-40,-7.1,-60.1,-10.5c-6,-1,-6.1,-0.8,-6.1,5.6c0,53,0,105.9,0,158.9c0,1,0,2,0,3 c0.2,2.6,1,4.1,4,4.6c10.1,1.7,20.1,3.9,30.2,5.8c27.3,5.1,54.6,10.1,81.9,15.2c22.1,4.2,44.1,8.6,66.2,12.8 c27.3,5.2,54.6,10.2,81.9,15.3c22.7,4.3,45.5,8.6,68.2,12.8c6.5,1.2,6.5,1.1,6.5,-5.7C409,272,409,244.7,409,217.4z" + android:fillColor="#E8E8E8"/> + <path + android:pathData="M412,129c-1.3,0,-2,-0.7,-2,-2C411.3,127,412,127.7,412,129z" + android:fillColor="#EAEAEA"/> + <path + android:pathData="M65.8,248.3c10.1,0.7,19.8,3.5,29.7,5.2c19,3.3,38,7,57,10.6c15.9,3,31.8,6.2,47.8,9.2 c24,4.6,48,9.1,72,13.7c14.6,2.8,29.3,5.5,43.8,8.5c22.5,4.6,45.3,8.4,67.9,12.6c4.1,0.8,8.2,1.8,12.4,3.8 c-6.4,2.1,-12.8,4.3,-19.2,6.4c-9.5,3.1,-19.1,5.8,-28.4,9.4c-6.7,2.6,-13.3,2.5,-20,1.3c-41.4,-7.6,-82.8,-15.2,-124.2,-22.8 c-32.6,-6,-65.2,-11.9,-97.8,-17.8c-13.7,-2.5,-27.4,-4.9,-41.1,-7.4C65.9,270,65.9,259.1,65.8,248.3z" + android:fillColor="#E6A3A3"/> + <path + android:pathData="M275,519c-1.5,3.9,-3.5,7.5,-3.3,12.1c0.1,2.9,-2.8,1.7,-4.7,1.4c-12,-2.2,-24.1,-4.3,-36.1,-6.6 c-15.3,-2.9,-30.5,-6,-45.8,-8.7c-5.1,-0.9,-7.5,-2.8,-7.5,-8.4c0,-3.2,-0.8,-6.5,-0.7,-9.9c12.2,2.3,24.4,4.6,36.5,7c19.8,3.9,39.5,8,59.3,12 C273.6,518.2,274.3,518.7,275,519z" + android:fillColor="#CBCBCA"/> + <path + android:pathData="M202.9,345.9c0,3.3,-0.1,6.7,0.1,10c0.2,3.9,-1.4,4.3,-4.9,3.7c-29.9,-5.6,-59.8,-11.2,-89.8,-16.5 c-3,-0.5,-3.5,-1.7,-3.4,-4.2c0.1,-3.3,0.1,-6.7,0.1,-10c21.7,3.9,43.4,7.9,65.2,11.6C181.1,342.4,191.8,345.3,202.9,345.9z" + android:fillColor="#CFCFCE"/> + <path + android:pathData="M65.8,248.3c0,10.9,0,21.7,0,32.6c-17.9,-3.1,-35.8,-6.2,-53.7,-9.3c0,-0.4,0,-0.7,0,-1.1 C30.1,263,48,255.6,65.8,248.3z" + android:fillColor="#E57474"/> + <path + android:pathData="M202.9,345.9c-11.1,-0.6,-21.8,-3.5,-32.6,-5.4c-21.8,-3.7,-43.5,-7.7,-65.2,-11.6c-0.6,-3.8,0.6,-5.6,4.8,-4.8 c28.3,5,56.6,9.9,84.9,14.9c1.1,0.2,2.3,0.8,3.4,0.8C202.8,339.6,203.4,342.3,202.9,345.9z" + android:fillColor="#BDBDBD"/> + <path + android:pathData="M367,876c7.8,-0.4,15,1.9,22,5C381.4,880.3,374.2,878.4,367,876z" + android:fillColor="#EFEFEE"/> + <path + android:pathData="M354,873c4.5,0.1,9.1,0.1,13,3C362.5,875.6,358.1,875,354,873z" + android:fillColor="#EFEFEE"/> + <path + android:pathData="M350,872c1.4,0.1,3,-0.5,4,1C352.6,872.9,351,873.5,350,872z" + android:fillColor="#EFEFEE"/> + <path + android:pathData="M274.1,705c1.9,3.6,1,7.5,0.6,11.2c-0.3,2.8,-2.5,3.1,-4.9,2.6c-29.7,-5.9,-59.3,-11.9,-89,-17.7 c-3.1,-0.6,-3.9,-1.9,-3.8,-4.6c0.1,-3.2,0,-6.3,0,-9.5c1.2,0,2.4,-0.1,3.5,0.1c19.2,3.8,38.4,7.7,57.6,11.4 C250.1,700.8,261.9,703.8,274.1,705z" + android:fillColor="#D6D6D5"/> + <path + android:pathData="M274.1,705c-12.1,-1.2,-24,-4.2,-35.9,-6.5c-19.2,-3.7,-38.4,-7.6,-57.6,-11.4c-1.1,-0.2,-2.3,-0.1,-3.5,-0.1 c-0.5,-4.2,0.7,-5.4,5.3,-4.5c29.5,5.7,59.1,11.1,88.7,16.5C275.3,699.7,275.1,702,274.1,705z" + android:fillColor="#C9C9C8"/> + <path + android:pathData="M409,217.4c0,27.3,0,54.6,0,82c0,6.8,0,6.9,-6.5,5.7c-22.7,-4.2,-45.5,-8.6,-68.2,-12.8 c-27.3,-5.1,-54.6,-10.1,-81.9,-15.3c-22.1,-4.2,-44.1,-8.6,-66.2,-12.8c-27.3,-5.2,-54.6,-10.1,-81.9,-15.2c-10.1,-1.9,-20.1,-4.1,-30.2,-5.8 c-3,-0.5,-3.9,-2.1,-4,-4.6c-0.1,-1,0,-2,0,-3c0,-53,0,-105.9,0,-158.9c0,-6.4,0,-6.6,6.1,-5.6c20,3.4,40,7,60.1,10.5c22.1,3.9,44.3,7.6,66.4,11.5 c17.7,3.1,35.5,6.3,53.2,9.4c24.1,4.2,48.2,8.4,72.3,12.6c23.4,4.1,46.9,8.2,70.3,12.6c10.8,2,10.7,2.3,10.7,13.2 C409,166.4,409,191.9,409,217.4z M283.9,146.9c0.4,-3.2,-0.2,-5.3,-4,-6c-29.7,-5,-59.4,-9.9,-89,-15.3c-4.8,-0.9,-5.2,0.7,-4.8,4.4 c0,3.5,-0.1,7,0,10.5c0,1.3,-0.4,3.2,1.4,3.3c2.9,0.1,5.3,1.8,8.1,2.3c13.8,2.4,27.6,4.9,41.4,7.4c13.3,2.4,26.5,5.1,39.8,7.4 c6.6,1.2,7.3,0.4,7.3,-6.5C284,151.9,283.9,149.4,283.9,146.9z" + android:fillColor="#E8E7E7"/> + <path + android:pathData="M283.9,146.9c0,2.5,0.1,5,0.1,7.5c0,6.9,-0.7,7.7,-7.3,6.5c-13.3,-2.4,-26.5,-5,-39.8,-7.4 c-13.8,-2.5,-27.6,-5.1,-41.4,-7.4c-2.8,-0.5,-5.2,-2.2,-8.1,-2.3c-1.8,-0.1,-1.4,-2,-1.4,-3.3c0,-3.5,0,-7,0,-10.5c1.9,0.3,3.9,0.7,5.8,1 c21.6,4,43.1,8.1,64.7,11.8C265.6,144.4,274.5,147.1,283.9,146.9z" + android:fillColor="#CFCFCE"/> + <path + android:pathData="M283.9,146.9c-9.3,0.2,-18.3,-2.5,-27.3,-4.1c-21.6,-3.7,-43.1,-7.8,-64.7,-11.8c-1.9,-0.4,-3.9,-0.7,-5.8,-1 c-0.4,-3.6,-0.1,-5.2,4.8,-4.4c29.6,5.4,59.3,10.4,89,15.3C283.7,141.6,284.3,143.7,283.9,146.9z" + android:fillColor="#BDBDBD"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/hourglass.xml b/packages/DocumentsUI/res/drawable/hourglass.xml new file mode 100644 index 000000000000..9b8d0e2946ba --- /dev/null +++ b/packages/DocumentsUI/res/drawable/hourglass.xml @@ -0,0 +1,168 @@ +<!-- +Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="421dp" + android:height="909dp" + android:viewportWidth="421.0" + android:viewportHeight="909.0"> + <path + android:pathData="M36,122.9c-2.8,-2.6,-5.7,-5.1,-8.3,-7.8c-5.6,-6,-9.2,-12.9,-8.8,-21.5c0.3,-7.5,0.6,-15,-0.1,-22.5 c-1.2,-14.1,5.5,-23.9,16,-31.9c16.7,-12.8,36.1,-19.6,56.1,-25.1c23.8,-6.5,48,-10.2,72.5,-12.3C168.6,1.3,174,2.2,179,0 c19.3,0,38.7,0,58,0c6,2.1,12.4,1.3,18.6,1.8c30.2,2.7,59.9,7.6,88.5,17.5c16.5,5.7,32.6,12.6,45.2,25.4c6.5,6.6,10.3,14,9.8,23.6 c-0.4,7.8,-0.5,15.7,0,23.4c0.6,10.3,-3.4,18.4,-10.6,25.2c-2.2,2,-4.4,4,-6.6,6c-3,2,-6.1,4,-9.1,5.9c-9.2,4.5,-18.5,9,-28.2,12.3 c-42.4,14.5,-86.3,18.8,-130.8,19.6c-10.9,0.2,-21.9,-0.4,-32.9,-0.7c-4.6,-0.4,-9.2,-0.8,-13.9,-1.1c-18.9,-1.1,-37.5,-3.9,-56,-7.6 c-15.3,-3.1,-30.2,-7.6,-44.9,-12.6c-7.6,-3.7,-15.3,-7.4,-22.9,-11.1C41.1,125.8,38.6,124.3,36,122.9z M41,72c2.9,6.9,7.1,12.6,13.1,17.2 c13,10,27.9,15.8,43.4,20.6c28.2,8.8,57.2,12.8,86.5,14c31.8,1.2,63.7,0.8,95.3,-4.6c25.3,-4.4,50.1,-10,72.9,-22.2 c10.8,-5.8,20,-13.1,24.7,-24.9c2.3,-11,-2.3,-19.5,-10.2,-26.4c-10.5,-9.2,-23.1,-14.9,-36.2,-19.6C295.2,13.4,258.4,9.7,221.2,8.1 c-11.1,-0.5,-22.2,0,-33.4,0.6c-21.4,1,-42.6,3.1,-63.6,7.3c-22.2,4.5,-44.1,10.3,-63.4,22.6C48.9,46.3,38.4,55.4,41,72z" + android:fillColor="#9F9F9F"/> + <path + android:pathData="M0,829c3.7,-2.8,4.7,-7.6,7.8,-10.9c2.6,-2.8,4.9,-5.7,9.2,-7.6c0,3.4,-0.1,6.5,0,9.5c0,1.5,-0.7,3.5,1.7,4 c0.4,3.3,1.4,6.4,2.9,9.4c3.8,7.7,10,13,16.8,17.9c9.2,6.7,19.7,10.8,29.8,15.5c-0.7,2.4,1.3,0.7,1.8,1.1l0,0c1.5,2.1,3.7,2.2,6,2 l0,0c0.8,0.6,1.5,1.4,2.4,1.7c9.5,2.7,18.9,5.8,28.7,7.4c3.6,0.6,7,3.5,10.9,1.1c2.4,0.4,4.8,0.8,7.1,1.2c0.2,1.5,1.3,1.6,2.5,1.8 c6.6,0.9,13.3,2.4,19.9,2.8c5.1,0.3,10.3,2.9,15.4,0.3c0.4,0,0.8,0.1,1.1,0.1c0.3,2.2,2.1,1.8,3.5,1.8c3.8,0,7.6,0,11.5,0 c1.1,1.4,2.7,1,4.1,1c17.2,0,34.5,0,51.7,0c1.4,0,3,0.4,4.1,-1c3.8,0,7.6,0,11.5,0c1.4,0,3.2,0.4,3.5,-1.8c9.4,-1,18.7,-2.1,28.1,-3.1 c6,1.3,11.6,0.4,16.9,-2.8c21.2,-4.2,42.1,-9.3,61.8,-18.4c15.8,-7.3,30.8,-15.8,38,-33.1c2.4,-2,1.9,-4.8,2.2,-7.4c0.3,-3,0,-6,0.1,-9 c0,-1,-0.3,-2.1,0.7,-2.7c1.1,-0.7,1.7,0.5,2.5,1c7.2,5,12.1,11.7,14.8,20c0.4,1.2,0.6,2.2,2.1,2.3c0,3.3,0,6.7,0,10 c-1.5,0,-1.8,1.1,-2.2,2.2c-3.8,10.2,-11.2,17.5,-20.1,23.3c-20.8,13.6,-44.1,21.2,-68.1,26.7c-29.2,6.7,-58.7,11,-88.7,11.7 c-1.6,0,-3.5,-0.5,-3.9,2c-18.7,0,-37.3,0,-56,0c-0.3,-2.5,-2.3,-1.9,-3.9,-2c-5.6,-0.1,-11.2,-0.5,-16.9,-0.8c-18.5,-1.2,-36.8,-3.8,-55,-7.3 C79.9,893.9,54,887,30.2,874C19,867.9,8.5,860.9,2.5,849C2,848,1.4,847,0,847C0,841,0,835,0,829z" + android:fillColor="#E6E4E4"/> + <path + android:pathData="M372.9,128.9c3,-2,6.1,-4,9.1,-5.9c-0.2,2.7,0.2,5.4,1,8c-1.5,1.6,-0.3,1.8,1,2c0.3,1,0.7,2,1,3 c-1.5,1.6,-0.3,1.8,1,2c0.7,2,1.3,4,2,6c-1.5,1.6,-0.3,1.8,1,2c0.3,1.7,0.7,3.3,1,5c-1,2.3,-0.6,4.1,2,5c4.9,23.8,9,47.6,8,72 c-3.5,1.5,-2.1,3.8,-1,6c-1,6,-2,12,-3,18c-1.3,1,-1.3,2,0,3c0,0.7,0,1.3,0,2c-2.1,0.4,-2.6,1.3,-1,3c0,0.3,0,0.7,0,1 c-1.3,0.2,-2.5,0.4,-1,2c0.4,2.1,-0.7,4,-1,6c-1.3,0.2,-2.5,0.4,-1,2c-3.7,9.3,-7.3,18.7,-11,28c-2.7,1.2,-4.2,2.9,-3,6 c-3.4,6.9,-7.8,13.3,-12.2,19.5c-6.1,8.6,-12.4,17.3,-19.4,25.2c-7.3,8.3,-15.5,15.8,-23.9,23c-11.9,10.3,-24.9,19.3,-38.1,27.7 c-12.2,7.8,-25.4,14.1,-38.4,20.5c-12.1,6,-18.5,15.8,-21,28.6c-1.5,7.8,-0.5,15.4,2,22.8c1.2,3.5,3.7,6.1,5.6,9.2 c5.4,8.6,14.8,10.5,22.6,15c15.3,9,30.8,17.7,45.3,28.1c14.4,10.4,28.2,21.5,40.5,34.1c10.1,10.4,18.5,22.2,26.8,34.3 c6.5,9.5,11.3,19.6,16.1,29.8c-1.5,1.6,-0.3,1.8,1,2c0.7,2,1.3,4,2,6c-1,2.3,-0.6,4.1,2,5c0.7,1.2,1.2,2.5,1,4c-1,2.3,-0.6,4.1,2,5 c1.2,12.3,4.6,24.1,5.7,36.5c0.8,8.4,1.4,16.8,1,25.1c-0.3,5.9,-1.1,12,-1.9,18c-1.2,8.7,-2.3,17.4,-4.2,25.9 c-1.5,6.6,-3.7,13.1,-5.6,19.6c-1.8,3.1,-2.9,6.5,-3.9,9.9c-3.4,6.4,-5.6,13.6,-11.9,18.2c-0.1,-3.8,1.6,-7.1,3,-10.4 c8.7,-20.9,13,-42.8,14.7,-65.1c1,-12.9,0.2,-25.8,-1.7,-38.7c-2.7,-18.5,-7.8,-36.2,-15.8,-53.1c-7.3,-15.4,-16.8,-29.3,-27.7,-42.4 c-2.7,-3.2,-6.3,-5.7,-9.6,-8.6c0.4,0.8,0.7,1.4,1,1.9c0.7,1.1,1.5,2.2,2.3,3.3c16.5,21.5,28.5,45.2,34.2,71.7c0.7,3.3,3.1,6.9,0.3,10.4 c-1,-1.9,-2.1,-3.7,-3.1,-5.6c-3.3,-6.3,-6.1,-12.9,-11.7,-17.6c-0.4,-0.9,-0.8,-1.8,-1.3,-2.6c-4,-6.3,-10.4,-10.4,-14.8,-16.2c0,-5.4,-2.7,-9.9,-4.8,-14.5 c-8.4,-18.6,-20.4,-34.9,-32.9,-50.8c-8.4,-10.8,-15.5,-22.8,-28.7,-28.8c-5.3,-2.4,-10,-6,-15.1,-8.6c-5.1,-2.6,-9.9,-6.4,-16.3,-5.2 c-5.2,1,-10.4,2.1,-15.3,4.1c-29.3,11.9,-48.4,34.1,-61.8,61.9c-0.3,0.3,-0.7,0.6,-1,1c-7.1,0.8,-13.9,2.9,-20.7,5.1 c-32.6,10.6,-61,27.4,-82.3,54.9c-9.2,11.6,-15.4,24.7,-18.9,39c-1.5,-1.1,-1.1,-2.7,-1.1,-4.1c-0.1,-9.6,0.3,-19.2,1.8,-28.7 c3.7,-22.6,11.8,-43.5,24,-62.8c12.6,-20,28.6,-36.9,47,-51.7c21.3,-17.3,44.6,-31.3,69.3,-42.9c14.5,-6.8,20,-18.8,21.8,-33.1 c1.8,-13.3,-4.9,-24.1,-12.2,-34.4c-3.6,-5,-7.4,-9.8,-13.2,-12.5c-5.8,-2.8,-11.6,-5.7,-17.4,-8.7c-22,-11.6,-42.6,-25.1,-61.1,-41.7 c-20.7,-18.6,-37.9,-40,-48.8,-65.9c-6.7,-15.7,-10.9,-32.1,-12,-49c-1.8,-27.1,2.1,-53.6,11.7,-79.1c3.8,-10.1,7.1,-20.4,13.3,-29.4 c14.7,5,29.6,9.5,44.9,12.6c18.5,3.7,37.2,6.5,56,7.6c4.6,0.3,9.3,0.7,13.9,1.1c0.2,3.6,-1.5,6.8,-2.6,10 c-11.9,33.6,-17.8,68.2,-17.2,103.8c0.2,9.7,1.3,19.4,2.7,29.1c3.8,24.6,11.4,47.7,26,68.1c12.2,17.1,28.4,28.6,49,33.4 c4.7,1.1,9.5,2.2,14.5,-0.5c18.7,-10.2,36.8,-21.2,53.7,-34.2c15.4,-11.9,29.4,-25.3,41.5,-40.5c12.9,-16.2,23.4,-33.8,30.4,-53.4 c6.4,-17.6,10.3,-35.6,10.9,-54.3c0.5,-15.9,0.2,-31.9,-3,-47.6C383.8,158.7,380.1,143.3,372.9,128.9z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M383,780c1.1,-3.4,2.1,-6.8,3.9,-9.9c7.8,7.1,12.8,15.2,12.2,26.4c-0.6,10.7,-0.3,21.5,-0.5,32.3 c-7.2,17.3,-22.2,25.8,-38,33.1c-19.7,9.1,-40.6,14.1,-61.8,18.4c-5.6,0.9,-11.3,1.9,-16.9,2.8c-9.4,1,-18.7,2.1,-28.1,3.1 c-5,0.3,-9.9,0.7,-14.9,1c-20,1.2,-40,0.9,-60,0c-5,-0.3,-9.9,-0.7,-14.9,-1c-0.4,0,-0.8,-0.1,-1.1,-0.1c-12.6,-1.6,-25.2,-3.2,-37.9,-4.8 c-2.4,-0.4,-4.8,-0.8,-7.1,-1.2c-2.6,-0.6,-5.1,-1.3,-7.7,-1.8c-11.6,-2,-22.6,-6.3,-34.2,-8.4c0,0,0,0,0,0c-1.7,-1.6,-3.7,-2.2,-6,-2c0,0,0,0,0,0 c-0.2,-1,-1.1,-0.9,-1.8,-1.1c-10.2,-4.7,-20.6,-8.8,-29.8,-15.5c-6.8,-4.9,-13,-10.2,-16.8,-17.9c-1.5,-3,-2.4,-6.1,-2.9,-9.4 c0.1,-10.3,0,-20.6,0.2,-30.9c0.1,-8.3,3.5,-15,10,-20.2c2,3.5,3.4,7.1,4.1,11c-1.1,0.8,-1,2,-1.1,3.1c-0.6,8.2,2.9,14.9,8.3,20.6 c8.9,9.6,20.4,15.4,32.3,20.2c17.9,7.2,36.5,11.9,55.4,15.4c20.1,3.7,40.3,5.7,60.6,6.5c21.4,0.8,42.8,0.4,64.2,-1.6 c19.8,-1.9,39.4,-4.6,58.7,-9.3c19.9,-4.8,39.3,-11.2,56.4,-22.9c7.8,-5.3,15.2,-11.3,17.4,-21C386.4,790.1,388.3,784.3,383,780z" + android:fillColor="#9F9F9F"/> + <path + android:pathData="M378,305c-1.2,-3.1,0.3,-4.8,3,-6C380.6,301.3,379.7,303.3,378,305z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M399,234c-1.1,-2.2,-2.5,-4.5,1,-6C399.7,230,400.8,232.2,399,234z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M392,156c-2.6,-0.9,-3,-2.7,-2,-5C391.4,152.4,391.6,154.2,392,156z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M389,636c-2.6,-0.9,-3,-2.7,-2,-5C388.4,632.4,388.6,634.2,389,636z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M392,645c-2.6,-0.9,-3,-2.7,-2,-5C391.4,641.4,391.6,643.2,392,645z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M396,255c-1.3,-1,-1.3,-2,0,-3C397.3,253,397.3,254,396,255z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M395,260c-1.6,-1.7,-1.1,-2.6,1,-3C395.7,258,395.3,259,395,260z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M384,133c-1.3,-0.2,-2.5,-0.4,-1,-2C383.8,131.4,384,132.2,384,133z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M385,625c-1.3,-0.2,-2.5,-0.4,-1,-2C384.8,623.4,385,624.2,385,625z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M392,271c-1.5,-1.6,-0.3,-1.8,1,-2C393,269.8,392.8,270.6,392,271z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M394,263c-1.5,-1.6,-0.3,-1.8,1,-2C395,261.8,394.8,262.6,394,263z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M386,138c-1.3,-0.2,-2.5,-0.4,-1,-2C385.8,136.4,386,137.2,386,138z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M389,146c-1.3,-0.2,-2.5,-0.4,-1,-2C388.8,144.4,389,145.2,389,146z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M33.1,783.9c-0.8,-3.9,-2.2,-7.6,-4.1,-11c-3.7,-11.7,-7.2,-23.5,-9.2,-35.5c-1.3,-7.6,-1.9,-15.4,-2.7,-23.2 c-0.6,-6.2,-0.9,-12.4,-1,-18.5c-0.2,-7.9,1.9,-15.7,2.3,-23.4c0.5,-10.1,2.9,-19.5,5.5,-29c6.3,-23.1,17.3,-43.9,31.5,-62.8 c23.4,-31.1,53.3,-54.7,86.9,-74.1c10.1,-5.8,20.3,-11.6,30.9,-16.2c11.7,-5.2,16.3,-14.9,18.8,-26.3c3.2,-14.9,-2.8,-26.6,-12.7,-37.1 c-1.8,-1.9,-3.9,-3.1,-6.2,-4.2c-23.7,-11.4,-46.4,-24.4,-67.2,-40.7c-16.2,-12.6,-31.3,-26.5,-44.2,-42.6c-16.2,-20.3,-28.8,-42.5,-36.2,-67.5 c-3.1,-10.6,-5.4,-21.3,-6.2,-32.4c-0.7,-9.6,-3.2,-19.3,-2,-28.8c0.8,-6.6,1.5,-13.4,1.9,-20c1,-15.2,4.9,-29.6,9.2,-44c1.7,-5.7,4,-11.3,6.4,-16.8 c0.9,-2.2,1.3,-4.4,1.3,-6.8c2.6,1.4,5.1,2.9,7.2,4.9c-0.6,0.8,-1.4,1.4,-1.8,2.3c-11.2,26.2,-16.2,53.8,-17.4,82.2 c-0.4,8.8,1,17.5,1.9,26.2c2,19.7,7.4,38.4,15.6,56.3c17.9,39.2,46.6,69.1,81.3,93.6c18.5,13.1,38.1,24.3,58.5,34.1 c3.3,1.6,6,3.7,8.1,6.5c8,10.6,12.6,22.1,9.6,35.7c-2.1,9.4,-6.5,17.9,-14.8,22.7c-8.2,4.7,-16.9,8.5,-25.3,12.9 c-22.5,12,-43.8,25.8,-62.6,43c-21.9,19.9,-40.8,42.1,-53.7,69.2C26.3,646.5,20.6,682,24.1,719c1.8,18.7,7,36.7,12.7,54.6 c5.9,18.7,18.2,30.9,35.3,38.9c15.4,7.2,31.5,12.2,48.1,15.8c1.6,0.4,4.3,-0.3,4.8,2.6c-18,-2.8,-35.4,-7.5,-52.3,-14.5 c-12.2,-5.1,-23.4,-11.4,-32.4,-21.4C37.2,791.7,36.5,787,33.1,783.9z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M372.9,128.9c7.2,14.3,10.9,29.8,14.1,45.4c3.2,15.7,3.5,31.6,3,47.6c-0.6,18.7,-4.6,36.7,-10.9,54.3 c-7.1,19.6,-17.6,37.2,-30.4,53.4c-12.1,15.2,-26.1,28.6,-41.5,40.5c-16.9,13,-35,24,-53.7,34.2c-5,2.7,-9.8,1.6,-14.5,0.5 c-20.6,-4.8,-36.8,-16.3,-49,-33.4c-14.6,-20.4,-22.3,-43.5,-26,-68.1c-1.5,-9.7,-2.6,-19.4,-2.7,-29.1c-0.6,-35.6,5.4,-70.2,17.2,-103.8 c1.2,-3.3,2.8,-6.4,2.6,-10c11,0.2,21.9,0.9,32.9,0.7c44.4,-0.8,88.4,-5.2,130.8,-19.6C354.4,137.9,363.7,133.5,372.9,128.9z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M377,72c-4.6,11.9,-13.9,19.1,-24.7,24.9c-22.9,12.2,-47.6,17.9,-72.9,22.2c-31.6,5.4,-63.5,5.9,-95.3,4.6 c-29.3,-1.1,-58.3,-5.1,-86.5,-14C82.1,105,67.2,99.1,54.2,89.2C48.2,84.6,43.9,78.8,41,72c3.9,-1.8,4.6,-6.2,7.3,-9 c10.3,-10.5,22.9,-16.9,36.5,-21.8c19.7,-7.1,40,-11.5,60.7,-14.5c19.4,-2.8,38.9,-3.9,58.4,-4.5c17.9,-0.6,35.8,0.8,53.6,2.8 c15,1.6,29.9,3.5,44.5,7.1c20,4.9,39.7,10.7,57.2,22.1C366.5,58.8,371.5,65.5,377,72z" + android:fillColor="#8D8E8E"/> + <path + android:pathData="M125,831c-0.4,-2.9,-3.2,-2.3,-4.8,-2.6c-16.6,-3.7,-32.7,-8.7,-48.1,-15.8c-17.1,-8,-29.4,-20.2,-35.3,-38.9 c-5.7,-17.9,-10.9,-35.9,-12.7,-54.6c-3.6,-37.1,2.1,-72.5,18.4,-106.4c13,-27.1,31.9,-49.3,53.7,-69.2c18.8,-17.1,40.2,-30.9,62.6,-43 c8.4,-4.5,17.1,-8.2,25.3,-12.9c8.4,-4.8,12.7,-13.3,14.8,-22.7c3.1,-13.6,-1.6,-25.1,-9.6,-35.7c-2.1,-2.8,-4.8,-4.9,-8.1,-6.5 c-20.4,-9.9,-40,-21.1,-58.5,-34.1c-34.7,-24.6,-63.4,-54.5,-81.3,-93.6c-8.2,-17.9,-13.6,-36.6,-15.6,-56.3c-0.9,-8.7,-2.3,-17.5,-1.9,-26.2 c1.2,-28.3,6.2,-55.9,17.4,-82.2c0.4,-0.9,1.2,-1.5,1.8,-2.3c7.6,3.7,15.3,7.4,22.9,11.1c-6.2,9,-9.5,19.3,-13.3,29.4 c-9.6,25.5,-13.5,52,-11.7,79.1c1.1,16.9,5.4,33.3,12,49c11,25.9,28.1,47.4,48.8,65.9c18.5,16.6,39.1,30.2,61.1,41.7 c5.7,3,11.5,5.9,17.4,8.7c5.8,2.8,9.7,7.6,13.2,12.5c7.3,10.3,14,21.1,12.2,34.4c-1.9,14.3,-7.4,26.3,-21.8,33.1 c-24.7,11.6,-48,25.7,-69.3,42.9c-18.3,14.9,-34.3,31.7,-47,51.7c-12.2,19.3,-20.3,40.2,-24,62.8c-1.6,9.6,-2,19.1,-1.8,28.7 c0,1.4,-0.4,3.1,1.1,4.1c-0.6,14.9,0.1,29.8,3,44.5c4.2,21.4,9.1,42.6,26,58.4c-0.2,2.3,0.9,4.1,2.2,5.9c8.8,12.3,22,18.6,35.3,24.1 c26.4,10.9,54.2,16.1,82.4,19.1c1.7,0.2,3,0.4,3,2.4c-4.5,0.7,-9,0.9,-13.4,0.5c-13.2,-1,-26.5,-1.9,-39.6,-4.1c-0.6,-2.4,-1.7,-2.3,-3.1,-0.6 c-1.3,-0.1,-2.6,-0.3,-3.9,-0.4c-0.6,-2.3,-1.6,-2.4,-3.1,-0.7c-0.6,-0.1,-1.3,-0.2,-1.9,-0.3c-0.6,-2.4,-1.7,-2.4,-3.1,-0.6 C126.2,831.2,125.6,831.1,125,831z" + android:fillColor="#E8E8E7"/> + <path + android:pathData="M377,72c-5.4,-6.4,-10.5,-13.2,-17.7,-17.9C341.7,42.7,322.1,36.9,302,32c-14.6,-3.6,-29.5,-5.5,-44.5,-7.1 c-17.8,-1.9,-35.7,-3.3,-53.6,-2.8c-19.5,0.6,-39,1.7,-58.4,4.5c-20.7,3,-41,7.4,-60.7,14.5C71.3,46.1,58.7,52.4,48.4,63 c-2.7,2.8,-3.5,7.2,-7.3,9c-2.6,-16.6,7.9,-25.6,19.8,-33.3c19.3,-12.3,41.2,-18.2,63.4,-22.6c21,-4.2,42.2,-6.3,63.6,-7.3 c11.1,-0.5,22.3,-1,33.4,-0.6c37.2,1.5,74,5.3,109.4,17.9c13.1,4.6,25.6,10.4,36.2,19.6C374.7,52.5,379.3,61,377,72z" + android:fillColor="#808080"/> + <path + android:pathData="M179,887.2c20,0.9,40,1.2,60,0c0,0.3,0,0.5,0,0.8c-1.1,1.4,-2.7,1,-4.1,1c-17.2,0,-34.5,0,-51.7,0 c-1.4,0,-3,0.4,-4.1,-1C179,887.7,179,887.5,179,887.2z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M76,869.9c11.6,2.2,22.6,6.5,34.2,8.4c2.6,0.4,5.2,1.2,7.7,1.8c-3.9,2.3,-7.3,-0.6,-10.9,-1.1 c-9.8,-1.6,-19.2,-4.7,-28.7,-7.4C77.5,871.3,76.8,870.5,76,869.9z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M125.1,881.3c12.6,1.6,25.2,3.2,37.9,4.8c-5.2,2.6,-10.3,0,-15.4,-0.3c-6.7,-0.4,-13.3,-1.9,-19.9,-2.8 C126.3,882.9,125.2,882.8,125.1,881.3z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M282,883.1c5.6,-0.9,11.3,-1.9,16.9,-2.8C293.7,883.4,288.1,884.4,282,883.1z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M179,887.2c0,0.3,0,0.5,0,0.8c-3.8,0,-7.6,0,-11.5,0c-1.4,0,-3.2,0.4,-3.5,-1.8C169,886.5,174,886.9,179,887.2z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M239,888c0,-0.3,0,-0.5,0,-0.8c5,-0.3,9.9,-0.7,14.9,-1c-0.3,2.2,-2.1,1.8,-3.5,1.8C246.6,888,242.8,888,239,888z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M70,867.9c2.3,-0.2,4.3,0.4,6,2C73.8,870.1,71.6,870,70,867.9z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M68.2,866.8c0.7,0.2,1.6,0.2,1.8,1.1C69.5,867.4,67.6,869.2,68.2,866.8z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M165,584c0.3,-0.3,0.7,-0.6,1,-1c10.5,-1.3,21,-3.3,31.5,-3.8c20.8,-1.1,41.4,0.7,61.7,5.4 c30.5,7,57.8,20.3,81.8,40.5c4.4,5.9,10.8,10,14.8,16.2c0.5,0.8,0.9,1.7,1.3,2.6c-2.4,4.1,-4.7,8.1,-7.1,12.2c-4,3.7,-6.3,8.9,-11,12 c-1.6,-0.1,-2.8,0.5,-4.1,1.5c-12.6,9.3,-26.7,15.6,-41.5,20.1c-31,9.4,-62.6,13.3,-95.1,11.6c-12.3,-0.6,-24.5,-1.5,-36.5,-3.4 c-4.5,-0.7,-5.3,0.5,-4.8,4.2c-0.5,0,-1,0.1,-1.5,0c-17.8,-3.9,-34.7,-10.3,-50.9,-18.7c-1,-0.5,-1.6,-1.1,-1.6,-2.3c2.3,-0.3,4.1,1.1,6.1,2 c14.2,6.2,28.9,10.6,44.1,13.3c2.5,0.4,3,0.2,2.4,-2.3c-2.5,-9.3,-3.7,-18.7,-4.8,-28.3c-1.5,-13.7,-0.3,-27.1,1.7,-40.5 C154.6,610.8,159.7,597.4,165,584z" + android:fillColor="#E57474"/> + <path + android:pathData="M103,681c0.1,1.1,0.7,1.8,1.6,2.3c16.2,8.4,33.1,14.8,50.9,18.7c0.5,0.1,1,0,1.5,0c0.6,0.4,1.3,0.7,1.9,1.1 c-0.1,2.7,1,5.2,1.9,7.6c6.5,17.8,16.5,33.6,27.5,48.8c12.5,17.1,27.1,32.1,45.1,43.6c6.6,4.2,13.7,7.3,20.5,11 c-15.6,2.8,-31.4,2.5,-47.1,2.4c-9.9,0,-19.9,-0.2,-29.8,-1.1c-18.2,-1.6,-36.2,-3.9,-54,-8.3c-18.1,-4.4,-35.9,-9.5,-51,-21.1 c-16.9,-15.8,-21.8,-37,-26,-58.4c-2.9,-14.7,-3.6,-29.6,-3,-44.5c3.5,-14.4,9.7,-27.4,18.9,-39c3.4,4.8,6.2,10.1,10.3,14.2 c6,6.1,11.6,13,19.7,16.8c0.5,0.8,1.2,1,2.1,1c0,0,0,0,0,0c0.3,0.3,0.7,0.7,1,1c0,0,0,0,0,0c0.3,0.3,0.7,0.7,1,1l0,0 c1,1.3,2.4,1.8,4,2l0,0C100.7,681.2,101.9,681,103,681L103,681z" + android:fillColor="#E6A3A3"/> + <path + android:pathData="M341,625c-24,-20.1,-51.3,-33.5,-81.8,-40.5c-20.3,-4.7,-41,-6.5,-61.7,-5.4c-10.5,0.6,-21,2.5,-31.5,3.8 c13.4,-27.8,32.5,-49.9,61.8,-61.9c4.9,-2,10.1,-3.1,15.3,-4.1c6.3,-1.2,11.2,2.6,16.3,5.2c5.2,2.6,9.9,6.2,15.1,8.6 c13.3,6,20.3,18,28.7,28.8c12.5,16,24.6,32.2,32.9,50.8C338.3,615.2,341,619.7,341,625z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M91.9,675c-8,-3.8,-13.6,-10.7,-19.7,-16.8c-4.1,-4.1,-6.9,-9.4,-10.3,-14.2c21.3,-27.5,49.8,-44.3,82.3,-54.9 c6.8,-2.2,13.6,-4.3,20.7,-5.1c-5.3,13.4,-10.4,26.9,-12.5,41.2c-2,13.4,-3.2,26.8,-1.7,40.5c1.1,9.6,2.3,19,4.8,28.3 c0.7,2.5,0.1,2.7,-2.4,2.3c-15.2,-2.6,-29.9,-7.1,-44.1,-13.3c-2,-0.9,-3.7,-2.3,-6.1,-2c0,0,0,0,0,0c-0.7,-1.2,-1.9,-1,-3,-1c0,0,0,0,0,0 c-0.3,-2.7,-2.4,-1.8,-4,-2c0,0,0,0,0,0c-0.3,-0.3,-0.7,-0.7,-1,-1c0,0,0,0,0,0c-0.3,-0.3,-0.7,-0.7,-1,-1c0,0,0,0,0,0 C93.6,675.2,92.8,675,91.9,675z" + android:fillColor="#D86868"/> + <path + android:pathData="M135,832.8c1.3,0.1,2.6,0.3,3.9,0.4c0.9,0.8,2,0.7,3.1,0.6c13.1,2.2,26.4,3,39.6,4.1 c4.5,0.3,9,0.2,13.4,-0.5c3.1,0.3,6.3,0.7,9.4,0.8c22.6,0.4,45.2,-0.9,67.6,-4.1c23.9,-3.3,47.4,-8.2,69.8,-17.6 c10.7,-4.5,21.4,-9.3,29.3,-18.3l0,0.1c6.2,-4.6,8.5,-11.8,11.9,-18.2c5.2,4.3,3.3,10.1,2.2,15c-2.2,9.7,-9.6,15.7,-17.4,21 c-17.1,11.7,-36.5,18.1,-56.4,22.9c-19.3,4.7,-38.9,7.4,-58.7,9.3c-21.4,2,-42.8,2.5,-64.2,1.6c-20.3,-0.8,-40.5,-2.8,-60.6,-6.5 c-19,-3.5,-37.6,-8.2,-55.4,-15.4c-11.9,-4.8,-23.4,-10.6,-32.3,-20.2c-5.3,-5.8,-8.9,-12.4,-8.3,-20.6c0.1,-1.2,0,-2.4,1.1,-3.1 c3.3,3.1,4.1,7.8,7.2,11.1c9,9.9,20.2,16.3,32.4,21.4c16.8,7,34.3,11.7,52.3,14.5c0.6,0.1,1.2,0.2,1.9,0.3c0.9,0.8,2,0.7,3.1,0.6 c0.6,0.1,1.3,0.2,1.9,0.3C132.8,833,133.9,833,135,832.8z" + android:fillColor="#999899"/> + <path + android:pathData="M371.9,667c2.8,-3.5,0.4,-7.1,-0.3,-10.4c-5.7,-26.6,-17.7,-50.3,-34.2,-71.7c-0.8,-1,-1.5,-2.2,-2.3,-3.3 c-0.3,-0.5,-0.6,-1.1,-1,-1.9c3.4,3,6.9,5.4,9.6,8.6c10.8,13.1,20.4,27,27.7,42.4c8,16.9,13.1,34.6,15.8,53.1 c1.9,12.9,2.6,25.8,1.7,38.7c-1.7,22.4,-6,44.3,-14.7,65.1c-1.4,3.3,-3.1,6.6,-3,10.4c0,0,0,-0.1,0,-0.1c-1.8,-0.3,-3.3,0.4,-4.7,1.2 c-6.3,3.7,-12.6,7.3,-19.4,10.2c-24,10.3,-48.8,14.5,-74.7,9.2c-4.2,-0.9,-9.4,-0.2,-12.4,-4.8c13.8,-2,27.6,-4.4,41.1,-8 c10,-2.7,20,-5.4,29,-10.8c1.5,-0.5,3.2,-0.9,4.6,-1.6c10.6,-5.1,19.5,-12.1,25.3,-22.6c4.7,-3.1,8.2,-10.7,6.9,-15c0.3,-1.4,0.6,-2.9,1,-4.3 c5.4,-16.2,7.5,-33.1,9,-50C378,689.7,375.5,678.3,371.9,667z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M371.9,667c3.6,11.3,6.1,22.7,5.1,34.6c-1.5,16.9,-3.6,33.8,-9,50c-0.5,1.4,-0.7,2.9,-1,4.3 c-2.3,5,-4.6,10,-6.9,15c-5.8,10.5,-14.7,17.5,-25.3,22.6c-1.5,0.7,-3.1,1.1,-4.6,1.6c-0.3,-2.1,0.3,-3.9,1.1,-5.7 c3.4,-7.4,6.4,-14.9,8.9,-22.6c6,-18.1,10,-36.5,12,-55.6c1.2,-11.6,0.9,-23.2,0.6,-34.8c-0.2,-6.8,-0.7,-13.8,-2.8,-20.5 c2.4,-4.1,4.7,-8.1,7.1,-12.2c5.6,4.7,8.4,11.3,11.7,17.6C369.8,663.3,370.8,665.2,371.9,667z" + android:fillColor="#E6A3A3"/> + <path + android:pathData="M260,814c2.9,4.6,8.1,3.9,12.4,4.8c25.9,5.3,50.7,1.1,74.7,-9.2c6.7,-2.9,13.1,-6.4,19.4,-10.2 c1.4,-0.9,2.9,-1.6,4.7,-1.2c-7.9,9.1,-18.6,13.8,-29.3,18.3c-22.3,9.4,-45.9,14.3,-69.8,17.6c-22.4,3.1,-45,4.4,-67.6,4.1 c-3.1,-0.1,-6.3,-0.5,-9.4,-0.8c-0.1,-2,-1.4,-2.2,-3,-2.4c-28.3,-3,-56,-8.2,-82.4,-19.1c-13.4,-5.5,-26.5,-11.8,-35.3,-24.1c-1.3,-1.8,-2.4,-3.6,-2.2,-5.9 c15.1,11.6,32.9,16.7,51,21.1c17.7,4.4,35.8,6.6,54,8.3c10,0.9,20,1.1,29.8,1.1c15.7,0.1,31.5,0.4,47.1,-2.4 C256,814,258,814,260,814z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M130,831.9c-1.1,0.1,-2.2,0.2,-3.1,-0.6C128.3,829.5,129.4,829.5,130,831.9z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M135,832.8c-1.1,0.1,-2.2,0.2,-3.1,-0.7C133.4,830.5,134.4,830.6,135,832.8z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M142,833.8c-1.1,0.1,-2.2,0.2,-3.1,-0.6C140.3,831.5,141.4,831.5,142,833.8z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M260,814c-2,0,-4,0,-6,0c-6.8,-3.7,-13.9,-6.8,-20.5,-11c-18,-11.5,-32.7,-26.4,-45.1,-43.6c-11,-15.2,-21,-31,-27.5,-48.8 c-0.9,-2.5,-2,-4.9,-1.9,-7.7c0.7,0,1.4,-0.1,2,0.1c16.2,4.6,33.1,5.3,49.6,5.3c10,0,20.1,-0.2,30.2,-1.3c19.5,-2,38.7,-5.3,57,-12.4 c15.6,-6,30.1,-13.9,41.3,-26.9c4.7,-3.1,7,-8.3,11,-12c2.1,6.7,2.6,13.7,2.8,20.5c0.3,11.6,0.6,23.1,-0.6,34.8c-2,19,-6,37.5,-12,55.6 c-2.6,7.7,-5.5,15.3,-8.9,22.6c-0.9,1.9,-1.5,3.7,-1.1,5.7c-9,5.4,-19,8.1,-29,10.8C287.6,809.6,273.8,811.9,260,814z" + android:fillColor="#E6A3A3"/> + <path + android:pathData="M339,668c-11.1,13,-25.7,20.8,-41.3,26.9c-18.3,7.1,-37.5,10.4,-57,12.4c-10.1,1,-20.3,1.3,-30.2,1.3 c-16.6,0,-33.4,-0.7,-49.6,-5.3c-0.6,-0.2,-1.3,-0.1,-2,-0.1c-0.6,-0.4,-1.3,-0.7,-1.9,-1.1c-0.4,-3.8,0.3,-5,4.8,-4.2c12.1,2,24.3,2.8,36.5,3.4 c32.4,1.7,64.1,-2.3,95.1,-11.6c14.8,-4.5,29,-10.8,41.5,-20.1C336.3,668.5,337.5,667.9,339,668z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M96,678c1.6,0.2,3.7,-0.7,4,2C98.4,679.8,97,679.3,96,678z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M100,680c1.1,0,2.3,-0.2,3,1C101.9,681,100.7,681.2,100,680z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M91.9,675c0.8,0,1.6,0.2,2.1,1C93.2,676,92.4,675.8,91.9,675z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M94,676c0.3,0.3,0.7,0.7,1,1C94.7,676.7,94.3,676.3,94,676z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M95,677c0.3,0.3,0.7,0.7,1,1C95.7,677.7,95.3,677.3,95,677z" + android:fillColor="#C5C5C5"/> + <path + android:pathData="M360,771c2.3,-5,4.6,-10,6.9,-15C368.2,760.3,364.7,767.8,360,771z" + android:fillColor="#EDECEC"/> +</vector> diff --git a/packages/DocumentsUI/res/layout/directory_cluster.xml b/packages/DocumentsUI/res/layout/directory_cluster.xml index 8245e53097cd..2fa09d39bdab 100644 --- a/packages/DocumentsUI/res/layout/directory_cluster.xml +++ b/packages/DocumentsUI/res/layout/directory_cluster.xml @@ -25,7 +25,7 @@ android:elevation="8dp" android:background="@color/material_grey_50"/> - <com.android.documentsui.DirectoryContainerView + <FrameLayout android:id="@+id/container_directory" android:layout_width="match_parent" android:layout_height="0dp" diff --git a/packages/DocumentsUI/res/layout/drawer_layout.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml index 0146f142114f..e3def054fa0d 100644 --- a/packages/DocumentsUI/res/layout/drawer_layout.xml +++ b/packages/DocumentsUI/res/layout/drawer_layout.xml @@ -32,7 +32,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - <com.android.documentsui.DocumentsToolBar + <com.android.documentsui.DocumentsToolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?android:attr/actionBarSize" @@ -48,7 +48,7 @@ android:layout_marginStart="4dp" android:overlapAnchor="true" /> - </com.android.documentsui.DocumentsToolBar> + </com.android.documentsui.DocumentsToolbar> <include layout="@layout/directory_cluster"/> diff --git a/packages/DocumentsUI/res/layout/fixed_layout.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml index 3135977e702c..8414febfb7ca 100644 --- a/packages/DocumentsUI/res/layout/fixed_layout.xml +++ b/packages/DocumentsUI/res/layout/fixed_layout.xml @@ -22,12 +22,12 @@ android:layout_height="match_parent" android:id="@+id/coordinator_layout"> - <LinearLayout + <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> - <com.android.documentsui.DocumentsToolBar + <com.android.documentsui.DocumentsToolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?android:attr/actionBarSize" @@ -43,7 +43,7 @@ android:layout_marginStart="4dp" android:overlapAnchor="true" /> - </com.android.documentsui.DocumentsToolBar> + </com.android.documentsui.DocumentsToolbar> <LinearLayout android:layout_width="match_parent" @@ -59,7 +59,6 @@ <include layout="@layout/directory_cluster" android:layout_width="0dp" - android:layout_weight="1" android:elevation="8dp" /> </LinearLayout> diff --git a/packages/DocumentsUI/res/layout/single_pane_layout.xml b/packages/DocumentsUI/res/layout/single_pane_layout.xml index c5a574568db0..f53d69808929 100644 --- a/packages/DocumentsUI/res/layout/single_pane_layout.xml +++ b/packages/DocumentsUI/res/layout/single_pane_layout.xml @@ -27,7 +27,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - <com.android.documentsui.DocumentsToolBar + <com.android.documentsui.DocumentsToolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?android:attr/actionBarSize" @@ -43,7 +43,7 @@ android:layout_marginStart="4dp" android:overlapAnchor="true" /> - </com.android.documentsui.DocumentsToolBar> + </com.android.documentsui.DocumentsToolbar> <include layout="@layout/directory_cluster"/> diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml index b791ef12b6f3..73571af20134 100644 --- a/packages/DocumentsUI/res/menu/activity.xml +++ b/packages/DocumentsUI/res/menu/activity.xml @@ -32,23 +32,6 @@ android:imeOptions="actionSearch" android:visible="false" /> <item - android:id="@+id/menu_sort" - android:title="@string/menu_sort" - android:icon="@drawable/ic_menu_sortby" - android:showAsAction="always"> - <menu> - <item - android:id="@+id/menu_sort_name" - android:title="@string/sort_name" /> - <item - android:id="@+id/menu_sort_date" - android:title="@string/sort_date" /> - <item - android:id="@+id/menu_sort_size" - android:title="@string/sort_size" /> - </menu> - </item> - <item android:id="@+id/menu_grid" android:title="@string/menu_grid" android:icon="@drawable/ic_menu_view_grid" @@ -70,7 +53,7 @@ android:title="@string/menu_create_dir" android:icon="@drawable/ic_menu_new_folder" android:alphabeticShortcut="e" - android:showAsAction="always" + android:showAsAction="never" android:visible="false" /> <item android:id="@+id/menu_paste_from_clipboard" @@ -80,6 +63,23 @@ android:visible="false" /> <!-- Copy action is defined in mode_directory.xml --> <item + android:id="@+id/menu_sort" + android:title="@string/menu_sort" + android:icon="@drawable/ic_menu_sortby" + android:showAsAction="never"> + <menu> + <item + android:id="@+id/menu_sort_name" + android:title="@string/sort_name" /> + <item + android:id="@+id/menu_sort_date" + android:title="@string/sort_date" /> + <item + android:id="@+id/menu_sort_size" + android:title="@string/sort_size" /> + </menu> + </item> + <item android:id="@+id/menu_file_size" android:showAsAction="never" android:visible="false" /> diff --git a/packages/DocumentsUI/res/values/layouts.xml b/packages/DocumentsUI/res/values/layouts.xml index 8ac1ac2bbbfc..c9308a19ebd8 100644 --- a/packages/DocumentsUI/res/values/layouts.xml +++ b/packages/DocumentsUI/res/values/layouts.xml @@ -15,7 +15,7 @@ --> <resources> - <item name="docs_activity" type="layout">@layout/drawer_layout</item> + <item name="documents_activity" type="layout">@layout/drawer_layout</item> <item name="files_activity" type="layout">@layout/drawer_layout</item> - <item name="manage_roots_activity" type="layout">@layout/single_pane_layout</item> + <item name="downloads_activity" type="layout">@layout/single_pane_layout</item> </resources> diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml index 3c49f167534e..b97918e7b9d1 100644 --- a/packages/DocumentsUI/res/values/strings.xml +++ b/packages/DocumentsUI/res/values/strings.xml @@ -101,7 +101,7 @@ <!-- Toast shown when creating a folder failed with an error [CHAR LIMIT=48] --> <string name="create_error">Failed to create folder</string> <!-- Error message shown when querying for a list of documents failed [CHAR LIMIT=48] --> - <string name="query_error">Failed to query documents</string> + <string name="query_error">Can\u2019t load content at the moment</string> <!-- Title of storage root location that contains recently modified or used documents [CHAR LIMIT=24] --> <string name="root_recent">Recent</string> @@ -123,7 +123,7 @@ <string name="no_results">No matches in %1$s</string> <!-- Toast shown when no app can be found to open the selected document [CHAR LIMIT=48] --> - <string name="toast_no_application">Can\'t open file</string> + <string name="toast_no_application">Can\u2019t open file</string> <!-- Toast shown when some of the selected documents failed to be deleted [CHAR LIMIT=48] --> <string name="toast_failed_delete">Unable to delete some documents</string> @@ -160,27 +160,27 @@ <string name="delete_preparing">Preparing for delete\u2026</string> <!-- Title of the copy error notification [CHAR LIMIT=48] --> <plurals name="copy_error_notification_title"> - <item quantity="one">Couldn\'t copy <xliff:g id="count" example="1">%1$d</xliff:g> file</item> - <item quantity="other">Couldn\'t copy <xliff:g id="count" example="2">%1$d</xliff:g> files</item> + <item quantity="one">Couldn\u2019t copy <xliff:g id="count" example="1">%1$d</xliff:g> file</item> + <item quantity="other">Couldn\u2019t copy <xliff:g id="count" example="2">%1$d</xliff:g> files</item> </plurals> <!-- Title of the move error notification [CHAR LIMIT=48] --> <plurals name="move_error_notification_title"> - <item quantity="one">Couldn\'t move <xliff:g id="count" example="1">%1$d</xliff:g> file</item> - <item quantity="other">Couldn\'t move <xliff:g id="count" example="2">%1$d</xliff:g> files</item> + <item quantity="one">Couldn\u2019t move <xliff:g id="count" example="1">%1$d</xliff:g> file</item> + <item quantity="other">Couldn\u2019t move <xliff:g id="count" example="2">%1$d</xliff:g> files</item> </plurals> <!-- Title of the delete error notification [CHAR LIMIT=48] --> <plurals name="delete_error_notification_title"> - <item quantity="one">Couldn\'t delete <xliff:g id="count" example="1">%1$d</xliff:g> file</item> - <item quantity="other">Couldn\'t delete <xliff:g id="count" example="2">%1$d</xliff:g> files</item> + <item quantity="one">Couldn\u2019t delete <xliff:g id="count" example="1">%1$d</xliff:g> file</item> + <item quantity="other">Couldn\u2019t delete <xliff:g id="count" example="2">%1$d</xliff:g> files</item> </plurals> <!-- Second line for notifications saying that more information will be shown after touching [CHAR LIMIT=48] --> <string name="notification_touch_for_details">Tap to view details</string> <!-- Label of the close dialog button.[CHAR LIMIT=24] --> <string name="close">Close</string> <!-- Contents of the copying failure alert dialog. [CHAR LIMIT=48] --> - <string name="copy_failure_alert_content">These files weren\'t copied: <xliff:g id="list">%1$s</xliff:g></string> + <string name="copy_failure_alert_content">These files weren\u2019t copied: <xliff:g id="list">%1$s</xliff:g></string> <!-- Contents of the moving failure alert dialog. [CHAR LIMIT=48] --> - <string name="move_failure_alert_content">These files weren\'t moved: <xliff:g id="list">%1$s</xliff:g></string> + <string name="move_failure_alert_content">These files weren\u2019t moved: <xliff:g id="list">%1$s</xliff:g></string> <!-- Contents of the copying warning dialog due to converted files. [CHAR LIMIT=64] --> <string name="copy_converted_warning_content">These files were converted to another format: <xliff:g id="list" example="Document.pdf, Photo.jpg, Song.ogg">%1$s</xliff:g></string> <!-- Toast shown when a user copies files to clipboard. --> diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java index 497eb0eb0440..3c21a214b19b 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -42,88 +42,93 @@ import android.support.annotation.CallSuper; import android.support.annotation.LayoutRes; import android.support.annotation.Nullable; import android.util.Log; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.TextView; - -import com.android.documentsui.RecentsProvider.ResumeColumns; +import android.widget.Spinner; + import com.android.documentsui.SearchManager.SearchManagerListener; import com.android.documentsui.State.ViewMode; import com.android.documentsui.dirlist.DirectoryFragment; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; -import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; import com.android.internal.util.Preconditions; -import libcore.io.IoUtils; - import java.io.FileNotFoundException; -import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.Executor; -public abstract class BaseActivity extends Activity implements SearchManagerListener { +public abstract class BaseActivity extends Activity + implements SearchManagerListener, NavigationView.Environment { static final String EXTRA_STATE = "state"; + // See comments where this const is referenced for details. + private static final int DRAWER_NO_FIDDLE_DELAY = 1500; + State mState; RootsCache mRoots; SearchManager mSearchManager; DrawerController mDrawer; - boolean mProductivityDevice; + NavigationView mNavigator; private final String mTag; + @LayoutRes private int mLayoutId; - private DirectoryContainerView mDirectoryContainer; + + // Track the time we opened the drawer in response to back being pressed. + // We use the time gap to figure out whether to close app or reopen the drawer. + private long mDrawerLastFiddled; public abstract void onDocumentPicked(DocumentInfo doc, @Nullable SiblingProvider siblings); public abstract void onDocumentsPicked(List<DocumentInfo> docs); abstract void onTaskFinished(Uri... uris); abstract void refreshDirectory(int anim); - abstract void updateActionBar(); - abstract void saveStackBlocking(); - abstract State buildState(); + /** Allows sub-classes to include information in a newly created State instance. */ + abstract void includeState(State initialState); public BaseActivity(@LayoutRes int layoutId, String tag) { mLayoutId = layoutId; mTag = tag; } + @CallSuper @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - mState = (icicle != null) - ? icicle.<State>getParcelable(EXTRA_STATE) - : buildState(); + setContentView(mLayoutId); + mDrawer = DrawerController.create(this); + mState = getState(icicle); Metrics.logActivityLaunch(this, mState, getIntent()); - setContentView(mLayoutId); - mRoots = DocumentsApplication.getRootsCache(this); + mRoots.setOnCacheUpdateListener( new RootsCache.OnCacheUpdateListener() { @Override public void onCacheUpdate() { - new HandleRootsChangedTask().execute(getCurrentRoot()); + new HandleRootsChangedTask(BaseActivity.this) + .execute(getCurrentRoot()); } }); - mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory); + mSearchManager = new SearchManager(this); + DocumentsToolbar toolbar = (DocumentsToolbar) findViewById(R.id.toolbar); + setActionBar(toolbar); + mNavigator = new NavigationView( + mDrawer, + toolbar, + (Spinner) findViewById(R.id.stack), + mState, + this); + // Base classes must update result in their onCreate. setResult(Activity.RESULT_CANCELED); } @@ -133,7 +138,7 @@ public abstract class BaseActivity extends Activity implements SearchManagerList boolean showMenu = super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.activity, menu); - mSearchManager.install((DocumentsToolBar) findViewById(R.id.toolbar)); + mSearchManager.install((DocumentsToolbar) findViewById(R.id.toolbar)); return showMenu; } @@ -178,7 +183,20 @@ public abstract class BaseActivity extends Activity implements SearchManagerList super.onDestroy(); } - State buildDefaultState() { + private State getState(@Nullable Bundle icicle) { + if (icicle != null) { + State state = icicle.<State>getParcelable(EXTRA_STATE); + if (DEBUG) Log.d(mTag, "Recovered existing state object: " + state); + return state; + } + + State state = createSharedState(); + includeState(state); + if (DEBUG) Log.d(mTag, "Created new state object: " + state); + return state; + } + + private State createSharedState() { State state = new State(); final Intent intent = getIntent(); @@ -201,6 +219,11 @@ public abstract class BaseActivity extends Activity implements SearchManagerList void onStackRestored(boolean restored, boolean external) {} void onRootPicked(RootInfo root) { + // Skip refreshing if root didn't change + if(root.equals(getCurrentRoot())) { + return; + } + mState.derivedMode = LocalPreferences.getViewMode(this, root, MODE_GRID); // Clear entire backstack and start in new root @@ -213,22 +236,7 @@ public abstract class BaseActivity extends Activity implements SearchManagerList if (mRoots.isRecentsRoot(root)) { refreshCurrentRootAndDirectory(ANIM_NONE); } else { - new PickRootTask(root).executeOnExecutor(getExecutorForCurrentDirectory()); - } - } - - void expandMenus(Menu menu) { - for (int i = 0; i < menu.size(); i++) { - final MenuItem item = menu.getItem(i); - switch (item.getItemId()) { - 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); - } + new PickRootTask(this, root).executeOnExecutor(getExecutorForCurrentDirectory()); } } @@ -336,10 +344,10 @@ public abstract class BaseActivity extends Activity implements SearchManagerList * The current directory name and selection will get updated. * @param anim */ - final void refreshCurrentRootAndDirectory(int anim) { + @Override + public final void refreshCurrentRootAndDirectory(int anim) { mSearchManager.cancelSearch(); - mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_ENTER); refreshDirectory(anim); final RootsFragment roots = RootsFragment.get(getFragmentManager()); @@ -347,8 +355,7 @@ public abstract class BaseActivity extends Activity implements SearchManagerList roots.onCurrentRootChanged(); } - updateActionBar(); - + mNavigator.update(); invalidateOptionsMenu(); } @@ -359,7 +366,6 @@ public abstract class BaseActivity extends Activity implements SearchManagerList */ @Override public void onSearchChanged() { - mDirectoryContainer.setDrawDisappearingFirst(false); refreshDirectory(ANIM_NONE); } @@ -484,6 +490,12 @@ public abstract class BaseActivity extends Activity implements SearchManagerList super.onRestoreInstanceState(state); } + @Override + public boolean isSearchExpanded() { + return mSearchManager.isExpanded(); + } + + @Override public RootInfo getCurrentRoot() { if (mState.stack.root != null) { return mState.stack.root; @@ -522,16 +534,35 @@ public abstract class BaseActivity extends Activity implements SearchManagerList return; } - final int size = mState.stack.size(); + int size = mState.stack.size(); + + // Do some "do what a I want" drawer fiddling, but don't + // do it if user already hit back recently and we recently + // did some fiddling. + if ((System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) { + // Close drawer if it is open. + if (mDrawer.isOpen()) { + mDrawer.setOpen(false); + mDrawerLastFiddled = System.currentTimeMillis(); + return; + } + + // Open the Close drawer if it is closed and we're at the top of a root. + if (size == 1) { + mDrawer.setOpen(true); + // Remember so we don't just close it again if back is pressed again. + mDrawerLastFiddled = System.currentTimeMillis(); + return; + } + } - if (mDrawer.isOpen()) { - mDrawer.setOpen(false); - } else if (size > 1) { + if (size > 1) { mState.stack.pop(); refreshCurrentRootAndDirectory(ANIM_LEAVE); - } else { - super.onBackPressed(); + return; } + + super.onBackPressed(); } public void onStackPicked(DocumentStack stack) { @@ -557,115 +588,40 @@ public abstract class BaseActivity extends Activity implements SearchManagerList } } - final class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> { + private static final class PickRootTask extends PairedTask<BaseActivity, Void, DocumentInfo> { private RootInfo mRoot; - public PickRootTask(RootInfo root) { + public PickRootTask(BaseActivity activity, RootInfo root) { + super(activity); mRoot = root; } @Override - protected DocumentInfo doInBackground(Void... params) { - return getRootDocumentBlocking(mRoot); + protected DocumentInfo run(Void... params) { + return mOwner.getRootDocumentBlocking(mRoot); } @Override - protected void onPostExecute(DocumentInfo result) { - if (result != null && !isDestroyed()) { - openContainerDocument(result); + protected void finish(DocumentInfo result) { + if (result != null) { + mOwner.openContainerDocument(result); } } } - final class RestoreStackTask extends AsyncTask<Void, Void, Void> { - private volatile boolean mRestoredStack; - private volatile boolean mExternal; - - @Override - protected Void doInBackground(Void... params) { - if (DEBUG && !mState.stack.isEmpty()) { - Log.w(mTag, "Overwriting existing stack."); - } - RootsCache roots = DocumentsApplication.getRootsCache(BaseActivity.this); - - // Restore last stack for calling package - final String packageName = getCallingPackageMaybeExtra(); - final Cursor cursor = getContentResolver() - .query(RecentsProvider.buildResume(packageName), null, null, null, null); - try { - if (cursor.moveToFirst()) { - mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0; - final byte[] rawStack = cursor.getBlob( - cursor.getColumnIndex(ResumeColumns.STACK)); - DurableUtils.readFromArray(rawStack, mState.stack); - mRestoredStack = true; - } - } catch (IOException e) { - Log.w(mTag, "Failed to resume: " + e); - } finally { - IoUtils.closeQuietly(cursor); - } - - if (mRestoredStack) { - // Update the restored stack to ensure we have freshest data - final Collection<RootInfo> matchingRoots = roots.getMatchingRootsBlocking(mState); - try { - mState.stack.updateRoot(matchingRoots); - mState.stack.updateDocuments(getContentResolver()); - } catch (FileNotFoundException e) { - Log.w(mTag, "Failed to restore stack: " + e); - mState.stack.reset(); - mRestoredStack = false; - } - } - - return null; - } - - @Override - protected void onPostExecute(Void result) { - if (isDestroyed()) return; - mState.restored = true; - refreshCurrentRootAndDirectory(ANIM_NONE); - onStackRestored(mRestoredStack, mExternal); - } - } - - final class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> { - private Uri mRootUri; - - public RestoreRootTask(Uri rootUri) { - mRootUri = rootUri; - } + private static final class HandleRootsChangedTask + extends PairedTask<BaseActivity, RootInfo, RootInfo> { + DocumentInfo mHome; - @Override - protected RootInfo doInBackground(Void... params) { - final String rootId = DocumentsContract.getRootId(mRootUri); - return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId); + public HandleRootsChangedTask(BaseActivity activity) { + super(activity); } @Override - protected void onPostExecute(RootInfo root) { - if (isDestroyed()) return; - mState.restored = true; - - if (root != null) { - onRootPicked(root); - } else { - Log.w(mTag, "Failed to find root: " + mRootUri); - finish(); - } - } - } - - final class HandleRootsChangedTask extends AsyncTask<RootInfo, Void, RootInfo> { - DocumentInfo mHome; - - @Override - protected RootInfo doInBackground(RootInfo... roots) { + protected RootInfo run(RootInfo... roots) { checkArgument(roots.length == 1); final RootInfo currentRoot = roots[0]; - final Collection<RootInfo> cachedRoots = mRoots.getRootsBlocking(); + final Collection<RootInfo> cachedRoots = mOwner.mRoots.getRootsBlocking(); RootInfo homeRoot = null; for (final RootInfo root : cachedRoots) { if (root.isHome()) { @@ -677,107 +633,21 @@ public abstract class BaseActivity extends Activity implements SearchManagerList } } Preconditions.checkNotNull(homeRoot); - mHome = getRootDocumentBlocking(homeRoot); + mHome = mOwner.getRootDocumentBlocking(homeRoot); return homeRoot; } @Override - protected void onPostExecute(RootInfo homeRoot) { - if (homeRoot != null && mHome != null && !isDestroyed()) { + protected void finish(RootInfo homeRoot) { + if (homeRoot != null && mHome != null) { // Clear entire backstack and start in new root - mState.onRootChanged(homeRoot); - mSearchManager.update(homeRoot); - openContainerDocument(mHome); + mOwner.mState.onRootChanged(homeRoot); + mOwner.mSearchManager.update(homeRoot); + mOwner.openContainerDocument(mHome); } } } - final class ItemSelectedListener implements OnItemSelectedListener { - - boolean mIgnoreNextNavigation; - - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - if (mIgnoreNextNavigation) { - mIgnoreNextNavigation = false; - return; - } - - while (mState.stack.size() > position + 1) { - mState.popDocument(); - } - refreshCurrentRootAndDirectory(ANIM_LEAVE); - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - // Ignored - } - } - - /** - * Class providing toolbar with runtime access to useful activity data. - */ - final class StackAdapter extends BaseAdapter { - @Override - public int getCount() { - return mState.stack.size(); - } - - @Override - public DocumentInfo getItem(int position) { - return mState.stack.get(mState.stack.size() - position - 1); - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_subdir_title, parent, false); - } - - final TextView title = (TextView) convertView.findViewById(android.R.id.title); - final DocumentInfo doc = getItem(position); - - if (position == 0) { - final RootInfo root = getCurrentRoot(); - title.setText(root.title); - } else { - title.setText(doc.displayName); - } - - return convertView; - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_subdir, parent, false); - } - - final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir); - final TextView title = (TextView) convertView.findViewById(android.R.id.title); - final DocumentInfo doc = getItem(position); - - if (position == 0) { - final RootInfo root = getCurrentRoot(); - title.setText(root.title); - subdir.setVisibility(View.GONE); - } else { - title.setText(doc.displayName); - subdir.setVisibility(View.VISIBLE); - } - - return convertView; - } - } - /** * Interface providing access to current view of documents * even when all documents are not homed to the same parent. diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java deleted file mode 100644 index 71ea8a9352f6..000000000000 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2013 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.documentsui; - -import android.content.Context; -import android.graphics.Canvas; -import android.util.AttributeSet; -import android.view.View; -import android.widget.FrameLayout; - -import java.util.ArrayList; - -public class DirectoryContainerView extends FrameLayout { - private boolean mDisappearingFirst = false; - - public DirectoryContainerView(Context context) { - super(context); - } - - public DirectoryContainerView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - final ArrayList<View> disappearing = mDisappearingChildren; - if (mDisappearingFirst && disappearing != null) { - for (int i = 0; i < disappearing.size(); i++) { - super.drawChild(canvas, disappearing.get(i), getDrawingTime()); - } - } - super.dispatchDraw(canvas); - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (mDisappearingFirst && mDisappearingChildren != null - && mDisappearingChildren.contains(child)) { - return false; - } - return super.drawChild(canvas, child, drawingTime); - } - - public void setDrawDisappearingFirst(boolean disappearingFirst) { - mDisappearingFirst = disappearingFirst; - } -} diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index b933d0a8744c..3485fe4446f5 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -16,6 +16,7 @@ package com.android.documentsui; +import static com.android.documentsui.Shared.DEBUG; import static com.android.documentsui.State.ACTION_CREATE; import static com.android.documentsui.State.ACTION_GET_CONTENT; import static com.android.documentsui.State.ACTION_OPEN; @@ -31,11 +32,12 @@ import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentValues; +import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import android.content.res.Resources; +import android.database.Cursor; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Parcelable; import android.provider.DocumentsContract; @@ -43,10 +45,6 @@ import android.support.design.widget.Snackbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; -import android.view.View; -import android.widget.BaseAdapter; -import android.widget.Spinner; -import android.widget.Toolbar; import com.android.documentsui.RecentsProvider.RecentColumns; import com.android.documentsui.RecentsProvider.ResumeColumns; @@ -56,23 +54,20 @@ import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; import com.android.documentsui.services.FileOperationService; +import libcore.io.IoUtils; + +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.Arrays; +import java.util.Collection; import java.util.List; public class DocumentsActivity extends BaseActivity { private static final int CODE_FORWARD = 42; private static final String TAG = "DocumentsActivity"; - private Toolbar mToolbar; - private Spinner mToolbarStack; - - private Toolbar mRootsToolbar; - - private ItemSelectedListener mStackListener; - private BaseAdapter mStackAdapter; - public DocumentsActivity() { - super(R.layout.docs_activity, TAG); + super(R.layout.documents_activity, TAG); } @Override @@ -81,18 +76,6 @@ public class DocumentsActivity extends BaseActivity { final Resources res = getResources(); - mDrawer = DrawerController.create(this); - mToolbar = (Toolbar) findViewById(R.id.toolbar); - - mStackAdapter = new StackAdapter(); - mStackListener = new ItemSelectedListener(); - mToolbarStack = (Spinner) findViewById(R.id.stack); - mToolbarStack.setOnItemSelectedListener(mStackListener); - - mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar); - - setActionBar(mToolbar); - if (mState.action == ACTION_CREATE) { final String mimeType = getIntent().getType(); final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE); @@ -118,16 +101,14 @@ public class DocumentsActivity extends BaseActivity { // In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent // talkback from reading aloud the default title, we clear it here. setTitle(""); - new RestoreStackTask().execute(); + new RestoreStackTask(this).execute(); } else { refreshCurrentRootAndDirectory(ANIM_NONE); } } @Override - State buildState() { - State state = buildDefaultState(); - + void includeState(State state) { final Intent intent = getIntent(); final String action = intent.getAction(); if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) { @@ -158,8 +139,6 @@ public class DocumentsActivity extends BaseActivity { state.transferMode = intent.getIntExtra(FileOperationService.EXTRA_OPERATION, FileOperationService.OPERATION_COPY); } - - return state; } @Override @@ -180,7 +159,7 @@ public class DocumentsActivity extends BaseActivity { } if (showDrawer) { - setRootsDrawerOpen(true); + mNavigator.revealRootsDrawer(true); } } @@ -217,74 +196,28 @@ public class DocumentsActivity extends BaseActivity { @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - mDrawer.syncState(); - updateActionBar(); - } - - public void setRootsDrawerOpen(boolean open) { - mDrawer.setOpen(open); + mDrawer.update(); + mNavigator.update(); } @Override - public void updateActionBar() { - if (mRootsToolbar != null) { - final String prompt = getIntent().getStringExtra(DocumentsContract.EXTRA_PROMPT); - if (prompt != null) { - mRootsToolbar.setTitle(prompt); + public String getDrawerTitle() { + String title = getIntent().getStringExtra(DocumentsContract.EXTRA_PROMPT); + if (title == null) { + if (mState.action == ACTION_OPEN || + mState.action == ACTION_GET_CONTENT || + mState.action == ACTION_OPEN_TREE) { + title = getResources().getString(R.string.title_open); + } else if (mState.action == ACTION_CREATE || + mState.action == ACTION_PICK_COPY_DESTINATION) { + title = getResources().getString(R.string.title_save); } else { - if (mState.action == ACTION_OPEN || - mState.action == ACTION_GET_CONTENT || - mState.action == ACTION_OPEN_TREE) { - mRootsToolbar.setTitle(R.string.title_open); - } else if (mState.action == ACTION_CREATE || - mState.action == ACTION_PICK_COPY_DESTINATION) { - mRootsToolbar.setTitle(R.string.title_save); - } + // If all else fails, just call it "Files". + title = getResources().getString(R.string.files_label); } } - if (mDrawer.isUnlocked()) { - mToolbar.setNavigationIcon(R.drawable.ic_hamburger); - mToolbar.setNavigationContentDescription(R.string.drawer_open); - mToolbar.setNavigationOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - setRootsDrawerOpen(true); - } - }); - } else { - mToolbar.setNavigationIcon(null); - mToolbar.setNavigationContentDescription(R.string.drawer_open); - mToolbar.setNavigationOnClickListener(null); - } - - if (mSearchManager.isExpanded()) { - mToolbar.setTitle(null); - mToolbarStack.setVisibility(View.GONE); - mToolbarStack.setAdapter(null); - } else { - if (mState.stack.size() <= 1) { - mToolbar.setTitle(getCurrentRoot().title); - mToolbarStack.setVisibility(View.GONE); - mToolbarStack.setAdapter(null); - } else { - mToolbar.setTitle(null); - mToolbarStack.setVisibility(View.VISIBLE); - mToolbarStack.setAdapter(mStackAdapter); - - mStackListener.mIgnoreNextNavigation = true; - mToolbarStack.setSelection(mStackAdapter.getCount() - 1); - } - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - boolean showMenu = super.onCreateOptionsMenu(menu); - - expandMenus(menu); - return showMenu; + return title; } @Override @@ -331,11 +264,6 @@ public class DocumentsActivity extends BaseActivity { } @Override - public boolean onOptionsItemSelected(MenuItem item) { - return mDrawer.onOptionsItemSelected(item) || super.onOptionsItemSelected(item); - } - - @Override void refreshDirectory(int anim) { final FragmentManager fm = getFragmentManager(); final RootInfo root = getCurrentRoot(); @@ -386,17 +314,23 @@ public class DocumentsActivity extends BaseActivity { } void onSaveRequested(DocumentInfo replaceTarget) { - new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory()); + new ExistingFinishTask(this, replaceTarget.derivedUri) + .executeOnExecutor(getExecutorForCurrentDirectory()); } void onSaveRequested(String mimeType, String displayName) { - new CreateFinishTask(mimeType, displayName).executeOnExecutor(getExecutorForCurrentDirectory()); + new CreateFinishTask(this, mimeType, displayName) + .executeOnExecutor(getExecutorForCurrentDirectory()); } @Override void onRootPicked(RootInfo root) { super.onRootPicked(root); - setRootsDrawerOpen(false); + mNavigator.revealRootsDrawer(false); + } + + public void setRootsDrawerOpen(boolean open) { + mNavigator.revealRootsDrawer(open); } @Override @@ -406,7 +340,8 @@ public class DocumentsActivity extends BaseActivity { openContainerDocument(doc); } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { // Explicit file picked, return - new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory()); + new ExistingFinishTask(this, doc.derivedUri) + .executeOnExecutor(getExecutorForCurrentDirectory()); } else if (mState.action == ACTION_CREATE) { // Replace selected file SaveFragment.get(fm).setReplaceTarget(doc); @@ -421,7 +356,8 @@ public class DocumentsActivity extends BaseActivity { for (int i = 0; i < size; i++) { uris[i] = docs.get(i).derivedUri; } - new ExistingFinishTask(uris).executeOnExecutor(getExecutorForCurrentDirectory()); + new ExistingFinishTask(this, uris) + .executeOnExecutor(getExecutorForCurrentDirectory()); } } @@ -436,11 +372,10 @@ public class DocumentsActivity extends BaseActivity { // Should not be reached. throw new IllegalStateException("Invalid mState.action."); } - new PickFinishTask(result).executeOnExecutor(getExecutorForCurrentDirectory()); + new PickFinishTask(this, result).executeOnExecutor(getExecutorForCurrentDirectory()); } - @Override - void saveStackBlocking() { + void writeStackToRecentsBlocking() { final ContentResolver resolver = getContentResolver(); final ContentValues values = new ContentValues(); @@ -501,69 +436,137 @@ public class DocumentsActivity extends BaseActivity { finish(); } + public static DocumentsActivity get(Fragment fragment) { return (DocumentsActivity) fragment.getActivity(); } - private final class PickFinishTask extends AsyncTask<Void, Void, Void> { + /** + * Restores the stack from Recents for the specified package. + */ + private static final class RestoreStackTask + extends PairedTask<DocumentsActivity, Void, Void> { + + private volatile boolean mRestoredStack; + private volatile boolean mExternal; + private State mState; + + public RestoreStackTask(DocumentsActivity activity) { + super(activity); + mState = activity.mState; + } + + @Override + protected Void run(Void... params) { + if (DEBUG && !mState.stack.isEmpty()) { + Log.w(TAG, "Overwriting existing stack."); + } + RootsCache roots = DocumentsApplication.getRootsCache(mOwner); + + String packageName = mOwner.getCallingPackageMaybeExtra(); + Uri resumeUri = RecentsProvider.buildResume(packageName); + Cursor cursor = mOwner.getContentResolver().query(resumeUri, null, null, null, null); + try { + if (cursor.moveToFirst()) { + mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0; + final byte[] rawStack = cursor.getBlob( + cursor.getColumnIndex(ResumeColumns.STACK)); + DurableUtils.readFromArray(rawStack, mState.stack); + mRestoredStack = true; + } + } catch (IOException e) { + Log.w(TAG, "Failed to resume: " + e); + } finally { + IoUtils.closeQuietly(cursor); + } + + if (mRestoredStack) { + // Update the restored stack to ensure we have freshest data + final Collection<RootInfo> matchingRoots = roots.getMatchingRootsBlocking(mState); + try { + mState.stack.updateRoot(matchingRoots); + mState.stack.updateDocuments(mOwner.getContentResolver()); + } catch (FileNotFoundException e) { + Log.w(TAG, "Failed to restore stack for package: " + packageName + + " because of error: "+ e); + mState.stack.reset(); + mRestoredStack = false; + } + } + + return null; + } + + @Override + protected void finish(Void result) { + mState.restored = true; + mOwner.refreshCurrentRootAndDirectory(ANIM_NONE); + mOwner.onStackRestored(mRestoredStack, mExternal); + } + } + + private static final class PickFinishTask extends PairedTask<DocumentsActivity, Void, Void> { private final Uri mUri; - public PickFinishTask(Uri uri) { + public PickFinishTask(DocumentsActivity activity, Uri uri) { + super(activity); mUri = uri; } @Override - protected Void doInBackground(Void... params) { - saveStackBlocking(); + protected Void run(Void... params) { + mOwner.writeStackToRecentsBlocking(); return null; } @Override - protected void onPostExecute(Void result) { - onTaskFinished(mUri); + protected void finish(Void result) { + mOwner.onTaskFinished(mUri); } } - final class ExistingFinishTask extends AsyncTask<Void, Void, Void> { + private static final class ExistingFinishTask extends PairedTask<DocumentsActivity, Void, Void> { private final Uri[] mUris; - public ExistingFinishTask(Uri... uris) { + public ExistingFinishTask(DocumentsActivity activity, Uri... uris) { + super(activity); mUris = uris; } @Override - protected Void doInBackground(Void... params) { - saveStackBlocking(); + protected Void run(Void... params) { + mOwner.writeStackToRecentsBlocking(); return null; } @Override - protected void onPostExecute(Void result) { - onTaskFinished(mUris); + protected void finish(Void result) { + mOwner.onTaskFinished(mUris); } } /** * Task that creates a new document in the background. */ - final class CreateFinishTask extends AsyncTask<Void, Void, Uri> { + private static final class CreateFinishTask extends PairedTask<DocumentsActivity, Void, Uri> { private final String mMimeType; private final String mDisplayName; - public CreateFinishTask(String mimeType, String displayName) { + public CreateFinishTask(DocumentsActivity activity, String mimeType, String displayName) { + super(activity); mMimeType = mimeType; mDisplayName = displayName; } @Override - protected void onPreExecute() { - setPending(true); + protected void prepare() { + mOwner.setPending(true); } @Override - protected Uri doInBackground(Void... params) { - final ContentResolver resolver = getContentResolver(); - final DocumentInfo cwd = getCurrentDirectory(); + protected Uri run(Void... params) { + final ContentResolver resolver = mOwner.getContentResolver(); + final DocumentInfo cwd = mOwner.getCurrentDirectory(); ContentProviderClient client = null; Uri childUri = null; @@ -579,22 +582,22 @@ public class DocumentsActivity extends BaseActivity { } if (childUri != null) { - saveStackBlocking(); + mOwner.writeStackToRecentsBlocking(); } return childUri; } @Override - protected void onPostExecute(Uri result) { + protected void finish(Uri result) { if (result != null) { - onTaskFinished(result); + mOwner.onTaskFinished(result); } else { Snackbars.makeSnackbar( - DocumentsActivity.this, R.string.save_error, Snackbar.LENGTH_SHORT).show(); + mOwner, R.string.save_error, Snackbar.LENGTH_SHORT).show(); } - setPending(false); + mOwner.setPending(false); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java index 547e343cdb0d..900544220cce 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsApplication.java @@ -63,6 +63,8 @@ public class DocumentsApplication extends Application { @Override public void onCreate() { + super.onCreate(); + final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); final int memoryClassBytes = am.getMemoryClass() * 1024 * 1024; diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsToolBar.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsToolbar.java index 36b764659c05..7742cbf226e8 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsToolBar.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsToolbar.java @@ -24,28 +24,28 @@ import android.widget.Toolbar; /** * ToolBar of Documents UI. */ -public class DocumentsToolBar extends Toolbar { +public class DocumentsToolbar extends Toolbar { interface OnActionViewCollapsedListener { void onActionViewCollapsed(); } private OnActionViewCollapsedListener mOnActionViewCollapsedListener; - public DocumentsToolBar(Context context, AttributeSet attrs, + public DocumentsToolbar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } - public DocumentsToolBar(Context context, AttributeSet attrs, + public DocumentsToolbar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } - public DocumentsToolBar(Context context, AttributeSet attrs) { + public DocumentsToolbar(Context context, AttributeSet attrs) { super(context, attrs); } - public DocumentsToolBar(Context context) { + public DocumentsToolbar(Context context) { super(context); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java index 5cc677c4f008..d589d5e0e237 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java @@ -24,8 +24,6 @@ import android.app.Fragment; import android.app.FragmentManager; import android.content.ActivityNotFoundException; import android.content.ClipData; -import android.content.ContentResolver; -import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -35,15 +33,10 @@ import android.support.design.widget.Snackbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; -import android.view.View; -import android.widget.BaseAdapter; -import android.widget.Spinner; import android.widget.Toolbar; -import com.android.documentsui.RecentsProvider.ResumeColumns; import com.android.documentsui.dirlist.DirectoryFragment; import com.android.documentsui.model.DocumentInfo; -import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; import com.android.internal.util.Preconditions; @@ -56,14 +49,8 @@ import java.util.List; public class DownloadsActivity extends BaseActivity { private static final String TAG = "DownloadsActivity"; - private Toolbar mToolbar; - private Spinner mToolbarStack; - - private ItemSelectedListener mStackListener; - private BaseAdapter mStackAdapter; - public DownloadsActivity() { - super(R.layout.manage_roots_activity, TAG); + super(R.layout.downloads_activity, TAG); } @Override @@ -72,73 +59,39 @@ public class DownloadsActivity extends BaseActivity { final Context context = this; - mDrawer = DrawerController.createDummy(); - - mToolbar = (Toolbar) findViewById(R.id.toolbar); - mToolbar.setTitleTextAppearance(context, + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + toolbar.setTitleTextAppearance(context, android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title); - mStackAdapter = new StackAdapter(); - mStackListener = new ItemSelectedListener(); - mToolbarStack = (Spinner) findViewById(R.id.stack); - mToolbarStack.setOnItemSelectedListener(mStackListener); - - setActionBar(mToolbar); - if (!mState.restored) { // In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent // talkback from reading aloud the default title, we clear it here. setTitle(""); final Uri rootUri = getIntent().getData(); - new RestoreRootTask(rootUri).executeOnExecutor(getExecutorForCurrentDirectory()); + new RestoreRootTask(this, rootUri).executeOnExecutor(getExecutorForCurrentDirectory()); } else { refreshCurrentRootAndDirectory(ANIM_NONE); } } @Override - State buildState() { - State state = buildDefaultState(); - + void includeState(State state) { state.action = ACTION_MANAGE; state.acceptMimes = new String[] { "*/*" }; state.allowMultiple = true; state.showSize = true; state.excludedAuthorities = getExcludedAuthorities(); - - return state; } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - updateActionBar(); + mNavigator.update(); } @Override - public void updateActionBar() { - // No navigation in manage root mode. - mToolbar.setNavigationIcon(null); - mToolbar.setNavigationOnClickListener(null); - - if (mSearchManager.isExpanded()) { - mToolbar.setTitle(null); - mToolbarStack.setVisibility(View.GONE); - mToolbarStack.setAdapter(null); - } else { - if (mState.stack.size() <= 1) { - mToolbar.setTitle(getCurrentRoot().title); - mToolbarStack.setVisibility(View.GONE); - mToolbarStack.setAdapter(null); - } else { - mToolbar.setTitle(null); - mToolbarStack.setVisibility(View.VISIBLE); - mToolbarStack.setAdapter(mStackAdapter); - - mStackListener.mIgnoreNextNavigation = true; - mToolbarStack.setSelection(mStackAdapter.getCount() - 1); - } - } + public String getDrawerTitle() { + return null; // being and nothingness } @Override @@ -147,14 +100,12 @@ public class DownloadsActivity extends BaseActivity { final MenuItem advanced = menu.findItem(R.id.menu_advanced); final MenuItem createDir = menu.findItem(R.id.menu_create_dir); - final MenuItem newWindow = menu.findItem(R.id.menu_new_window); final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard); final MenuItem fileSize = menu.findItem(R.id.menu_file_size); advanced.setVisible(false); createDir.setVisible(false); pasteFromCb.setEnabled(false); - newWindow.setEnabled(false); fileSize.setVisible(false); Menus.disableHiddenItems(menu); @@ -209,21 +160,6 @@ public class DownloadsActivity extends BaseActivity { public void onDocumentsPicked(List<DocumentInfo> docs) {} @Override - void saveStackBlocking() { - final ContentResolver resolver = getContentResolver(); - final ContentValues values = new ContentValues(); - - final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack); - - // Remember location for next app launch - final String packageName = getCallingPackageMaybeExtra(); - values.clear(); - values.put(ResumeColumns.STACK, rawStack); - values.put(ResumeColumns.EXTERNAL, 0); - resolver.insert(RecentsProvider.buildResume(packageName), values); - } - - @Override void onTaskFinished(Uri... uris) { Log.d(TAG, "onFinished() " + Arrays.toString(uris)); diff --git a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java index df3ac1b0e7ef..bcf69c44070a 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java @@ -22,8 +22,8 @@ import android.app.Activity; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout.DrawerListener; -import android.view.MenuItem; import android.view.View; +import android.widget.Toolbar; /** * A facade over the various pieces comprising "roots fragment in a Drawer". @@ -33,13 +33,10 @@ import android.view.View; abstract class DrawerController implements DrawerListener { abstract void setOpen(boolean open); - abstract void lockOpen(); - abstract void lockClosed(); abstract boolean isPresent(); abstract boolean isOpen(); - abstract boolean isUnlocked(); - abstract void syncState(); - abstract boolean onOptionsItemSelected(MenuItem item); + abstract void setTitle(String title); + abstract void update(); /** * Returns a controller suitable for {@code Layout}. @@ -53,6 +50,8 @@ abstract class DrawerController implements DrawerListener { } View drawer = activity.findViewById(R.id.drawer_roots); + Toolbar toolbar = (Toolbar) activity.findViewById(R.id.roots_toolbar); + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( activity, layout, @@ -60,7 +59,7 @@ abstract class DrawerController implements DrawerListener { R.string.drawer_open, R.string.drawer_close); - return new RuntimeDrawerController(layout, drawer, toggle); + return new RuntimeDrawerController(layout, drawer, toggle, toolbar); } /** @@ -78,9 +77,12 @@ abstract class DrawerController implements DrawerListener { private final ActionBarDrawerToggle mToggle; private DrawerLayout mLayout; private View mDrawer; + private Toolbar mToolbar; public RuntimeDrawerController( - DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle) { + DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle, + Toolbar drawerToolbar) { + mToolbar = drawerToolbar; checkArgument(layout != null); mLayout = layout; @@ -110,28 +112,13 @@ abstract class DrawerController implements DrawerListener { } @Override - void syncState() { - mToggle.syncState(); + void setTitle(String title) { + mToolbar.setTitle(title); } @Override - boolean isUnlocked() { - return mLayout.getDrawerLockMode(mDrawer) == DrawerLayout.LOCK_MODE_UNLOCKED; - } - - @Override - void lockOpen() { - mLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN); - } - - @Override - void lockClosed() { - mLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); - } - - @Override - boolean onOptionsItemSelected(MenuItem item) { - return false; + void update() { + mToggle.syncState(); } @Override @@ -163,14 +150,6 @@ abstract class DrawerController implements DrawerListener { @Override void setOpen(boolean open) {} - @Override - void syncState() {} - - @Override - void lockOpen() {} - - @Override - void lockClosed() {} @Override boolean isOpen() { @@ -178,19 +157,15 @@ abstract class DrawerController implements DrawerListener { } @Override - boolean isUnlocked() { - return true; - } - - @Override boolean isPresent() { return false; } @Override - boolean onOptionsItemSelected(MenuItem item) { - return false; - } + void setTitle(String title) {} + + @Override + void update() {} @Override public void onDrawerSlide(View drawerView, float slideOffset) {} diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java index 064535a6a5cb..c81f342822f6 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java @@ -30,7 +30,6 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Parcelable; import android.provider.DocumentsContract; @@ -40,10 +39,6 @@ import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; -import android.view.View; -import android.widget.BaseAdapter; -import android.widget.Spinner; -import android.widget.Toolbar; import com.android.documentsui.OperationDialogFragment.DialogType; import com.android.documentsui.RecentsProvider.ResumeColumns; @@ -67,10 +62,6 @@ public class FilesActivity extends BaseActivity { public static final String TAG = "FilesActivity"; - private Toolbar mToolbar; - private Spinner mToolbarStack; - private ItemSelectedListener mStackListener; - private BaseAdapter mStackAdapter; private DocumentClipper mClipper; public FilesActivity() { @@ -81,17 +72,7 @@ public class FilesActivity extends BaseActivity { public void onCreate(Bundle icicle) { super.onCreate(icicle); - mToolbar = (Toolbar) findViewById(R.id.toolbar); - - mStackAdapter = new StackAdapter(); - mStackListener = new ItemSelectedListener(); - mToolbarStack = (Spinner) findViewById(R.id.stack); - mToolbarStack.setOnItemSelectedListener(mStackListener); - - setActionBar(mToolbar); - mClipper = new DocumentClipper(this); - mDrawer = DrawerController.create(this); RootsFragment.show(getFragmentManager(), null); @@ -116,19 +97,19 @@ public class FilesActivity extends BaseActivity { refreshCurrentRootAndDirectory(ANIM_NONE); } else if (intent.getAction() == Intent.ACTION_VIEW) { checkArgument(uri != null); - new OpenUriForViewTask().executeOnExecutor( + new OpenUriForViewTask(this).executeOnExecutor( ProviderExecutor.forAuthority(uri.getAuthority()), uri); } else if (DocumentsContract.isRootUri(this, uri)) { if (DEBUG) Log.d(TAG, "Launching with root URI."); // If we've got a specific root to display, restore that root using a dedicated // authority. That way a misbehaving provider won't result in an ANR. - new RestoreRootTask(uri).executeOnExecutor( + new RestoreRootTask(this, uri).executeOnExecutor( ProviderExecutor.forAuthority(uri.getAuthority())); } else { if (DEBUG) Log.d(TAG, "Launching into Home directory."); // If all else fails, try to load "Home" directory. final Uri homeUri = DocumentsContract.buildHomeUri(); - new RestoreRootTask(homeUri).executeOnExecutor( + new RestoreRootTask(this, homeUri).executeOnExecutor( ProviderExecutor.forAuthority(homeUri.getAuthority())); } @@ -152,9 +133,7 @@ public class FilesActivity extends BaseActivity { } @Override - State buildState() { - State state = buildDefaultState(); - + void includeState(State state) { final Intent intent = getIntent(); state.action = State.ACTION_BROWSE; @@ -167,8 +146,6 @@ public class FilesActivity extends BaseActivity { if (stack != null) { state.stack = stack; } - - return state; } @Override @@ -179,11 +156,11 @@ public class FilesActivity extends BaseActivity { // serach. Why? Because this avoid an early (undesired) load of // the recents root...which is the default root in other activities. // In Files app "Home" is the default, but it is loaded async. - // updateActionBar will be called once Home root is loaded. + // update will be called once Home root is loaded. // Except while searching we need this call to ensure the // search bits get layed out correctly. if (mSearchManager.isSearching()) { - updateActionBar(); + mNavigator.update(); } } @@ -203,52 +180,8 @@ public class FilesActivity extends BaseActivity { } @Override - public void updateActionBar() { - final RootInfo root = getCurrentRoot(); - - if (mDrawer.isPresent()) { - mToolbar.setNavigationIcon(R.drawable.ic_hamburger); - mToolbar.setNavigationContentDescription(R.string.drawer_open); - mToolbar.setNavigationOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - mDrawer.setOpen(true); - } - }); - } else { - mToolbar.setNavigationIcon( - root != null ? root.loadToolbarIcon(mToolbar.getContext()) : null); - mToolbar.setNavigationContentDescription(R.string.drawer_open); - mToolbar.setNavigationOnClickListener(null); - } - - if (mSearchManager.isExpanded()) { - mToolbar.setTitle(null); - mToolbarStack.setVisibility(View.GONE); - mToolbarStack.setAdapter(null); - } else { - if (mState.stack.size() <= 1) { - mToolbar.setTitle(root.title); - mToolbarStack.setVisibility(View.GONE); - mToolbarStack.setAdapter(null); - } else { - mToolbar.setTitle(null); - mToolbarStack.setVisibility(View.VISIBLE); - mToolbarStack.setAdapter(mStackAdapter); - - mStackListener.mIgnoreNextNavigation = true; - mToolbarStack.setSelection(mStackAdapter.getCount() - 1); - } - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - boolean showMenu = super.onCreateOptionsMenu(menu); - - expandMenus(menu); - return showMenu; + public String getDrawerTitle() { + return getResources().getString(R.string.files_label); } @Override @@ -260,15 +193,13 @@ public class FilesActivity extends BaseActivity { final MenuItem createDir = menu.findItem(R.id.menu_create_dir); final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard); final MenuItem settings = menu.findItem(R.id.menu_settings); + final MenuItem newWindow = menu.findItem(R.id.menu_new_window); createDir.setVisible(true); createDir.setEnabled(canCreateDirectory()); pasteFromCb.setEnabled(mClipper.hasItemsToPaste()); settings.setVisible(root.hasSettings()); - - // TODO: For some reason settings menu item is not - // honoring the "showAsAction=never" setting in activity.xml. - settings.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + newWindow.setVisible(true); Menus.disableHiddenItems(menu, pasteFromCb); return true; @@ -417,13 +348,15 @@ public class FilesActivity extends BaseActivity { } } - @Override - void saveStackBlocking() { + // Turns out only DocumentsActivity was ever calling saveStackBlocking. + // There may be a case where we want to contribute entries from + // Behavior here in FilesActivity, but it isn't yet obvious. + // TODO: Contribute to recents, or remove this. + void writeStackToRecentsBlocking() { final ContentResolver resolver = getContentResolver(); final ContentValues values = new ContentValues(); - final byte[] rawStack = DurableUtils.writeToArrayOrNull( - getDisplayState().stack); + final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack); // Remember location for next app launch final String packageName = getCallingPackageMaybeExtra(); @@ -462,12 +395,19 @@ public class FilesActivity extends BaseActivity { * to know which root to select. Also, the stack doesn't contain intermediate directories. * It's primarly used for opening ZIP archives from Downloads app. */ - final class OpenUriForViewTask extends AsyncTask<Uri, Void, Void> { + private static final class OpenUriForViewTask extends PairedTask<FilesActivity, Uri, Void> { + + private final State mState; + public OpenUriForViewTask(FilesActivity activity) { + super(activity); + mState = activity.mState; + } + @Override - protected Void doInBackground(Uri... params) { + protected Void run(Uri... params) { final Uri uri = params[0]; - final RootsCache rootsCache = DocumentsApplication.getRootsCache(FilesActivity.this); + final RootsCache rootsCache = DocumentsApplication.getRootsCache(mOwner); final String authority = uri.getAuthority(); final Collection<RootInfo> roots = @@ -480,20 +420,17 @@ public class FilesActivity extends BaseActivity { final RootInfo root = roots.iterator().next(); mState.stack.root = root; try { - mState.stack.add(DocumentInfo.fromUri(getContentResolver(), uri)); + mState.stack.add(DocumentInfo.fromUri(mOwner.getContentResolver(), uri)); } catch (FileNotFoundException e) { Log.e(TAG, "Failed to resolve DocumentInfo from Uri: " + uri); } - mState.stack.add(getRootDocumentBlocking(root)); + mState.stack.add(mOwner.getRootDocumentBlocking(root)); return null; } @Override - protected void onPostExecute(Void result) { - if (isDestroyed()) { - return; - } - refreshCurrentRootAndDirectory(ANIM_NONE); + protected void finish(Void result) { + mOwner.refreshCurrentRootAndDirectory(ANIM_NONE); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/ListItem.java b/packages/DocumentsUI/src/com/android/documentsui/ListItem.java index 5c40f1b20d74..6d6f21ea30bd 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/ListItem.java +++ b/packages/DocumentsUI/src/com/android/documentsui/ListItem.java @@ -20,7 +20,6 @@ import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.util.TypedValue; -import android.view.View; import android.widget.LinearLayout; /** @@ -39,14 +38,11 @@ public class ListItem extends LinearLayout @Override protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { - View indicator = findViewById(R.id.focus_indicator); - if (gainFocus) { - TypedValue color = new TypedValue(); - getContext().getTheme().resolveAttribute(android.R.attr.colorAccent, color, true); - indicator.setBackgroundColor(color.data); - } else { - indicator.setBackgroundColor(android.R.color.transparent); - } + TypedValue color = new TypedValue(); + int colorId = gainFocus ? android.R.attr.colorAccent : android.R.color.transparent; + getContext().getTheme().resolveAttribute(colorId, color, true); + + findViewById(R.id.focus_indicator).setBackgroundColor(color.data); super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java new file mode 100644 index 000000000000..ff1940aea94d --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/NavigationView.java @@ -0,0 +1,246 @@ +/* + * 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.documentsui; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; +import static com.android.documentsui.Shared.DEBUG; +import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_LEAVE; + +import android.annotation.Nullable; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.Spinner; +import android.widget.TextView; + +import com.android.documentsui.model.DocumentInfo; +import com.android.documentsui.model.RootInfo; + +/** + * A facade over the portions of the app and drawer toolbars. + */ +class NavigationView { + + private static final String TAG = "NavigationView"; + + private final DrawerController mDrawer; + private final DocumentsToolbar mToolbar; + private final Spinner mBreadcrumb; + private final State mState; + private final NavigationView.Environment mEnv; + private final BreadcrumbAdapter mBreadcrumbAdapter; + + private boolean mIgnoreNextNavigation; + + public NavigationView( + DrawerController drawer, + DocumentsToolbar toolbar, + Spinner breadcrumb, + State state, + NavigationView.Environment env) { + + mToolbar = toolbar; + mBreadcrumb = breadcrumb; + mDrawer = drawer; + mState = state; + mEnv = env; + + mBreadcrumbAdapter = new BreadcrumbAdapter(mState, mEnv); + mToolbar.setNavigationOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + onNavigationIconClicked(); + } + + }); + + mBreadcrumb.setOnItemSelectedListener( + new OnItemSelectedListener() { + @Override + public void onItemSelected( + AdapterView<?> parent, View view, int position, long id) { + onBreadcrumbItemSelected(position); + } + + @Override + public void onNothingSelected(AdapterView<?> parent) {} + }); + + } + + private void onNavigationIconClicked() { + if (mDrawer.isPresent()) { + mDrawer.setOpen(true); + } + } + + private void onBreadcrumbItemSelected(int position) { + if (mIgnoreNextNavigation) { + mIgnoreNextNavigation = false; + return; + } + + while (mState.stack.size() > position + 1) { + mState.popDocument(); + } + mEnv.refreshCurrentRootAndDirectory(ANIM_LEAVE); + } + + void update() { + + // TODO: Looks to me like this block is never getting hit. + if (mEnv.isSearchExpanded()) { + mToolbar.setTitle(null); + mBreadcrumb.setVisibility(View.GONE); + mBreadcrumb.setAdapter(null); + return; + } + + mDrawer.setTitle(mEnv.getDrawerTitle()); + + mToolbar.setNavigationIcon(getActionBarIcon()); + mToolbar.setNavigationContentDescription(R.string.drawer_open); + + if (mState.stack.size() <= 1) { + showBreadcrumb(false); + String title = mEnv.getCurrentRoot().title; + if (DEBUG) Log.d(TAG, "New toolbar title is: " + title); + mToolbar.setTitle(title); + } else { + showBreadcrumb(true); + mToolbar.setTitle(null); + mIgnoreNextNavigation = true; + mBreadcrumb.setSelection(mBreadcrumbAdapter.getCount() - 1); + } + + if (DEBUG) Log.d(TAG, "Final toolbar title is: " + mToolbar.getTitle()); + } + + private void showBreadcrumb(boolean visibility) { + if (visibility) { + mBreadcrumb.setVisibility(VISIBLE); + mBreadcrumb.setAdapter(mBreadcrumbAdapter); + } else { + mBreadcrumb.setVisibility(GONE); + mBreadcrumb.setAdapter(null); + } + } + + // Hamburger if drawer is present, else root icon, or sad nullness. + private @Nullable Drawable getActionBarIcon() { + if (mDrawer.isPresent()) { + return mToolbar.getContext().getDrawable(R.drawable.ic_hamburger); + } else { + RootInfo root = mEnv.getCurrentRoot(); + if (root != null) { + return root.loadToolbarIcon(mToolbar.getContext()); + } + } + return null; + } + + void revealRootsDrawer(boolean open) { + mDrawer.setOpen(open); + } + + /** + * Class providing toolbar with runtime access to useful activity data. + */ + static final class BreadcrumbAdapter extends BaseAdapter { + + private Environment mEnv; + private State mState; + + public BreadcrumbAdapter(State state, Environment env) { + mState = state; + mEnv = env; + } + + @Override + public int getCount() { + return mState.stack.size(); + } + + @Override + public DocumentInfo getItem(int position) { + return mState.stack.get(mState.stack.size() - position - 1); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_subdir_title, parent, false); + } + + final TextView title = (TextView) convertView.findViewById(android.R.id.title); + final DocumentInfo doc = getItem(position); + + if (position == 0) { + final RootInfo root = mEnv.getCurrentRoot(); + title.setText(root.title); + } else { + title.setText(doc.displayName); + } + + return convertView; + } + + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_subdir, parent, false); + } + + final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir); + final TextView title = (TextView) convertView.findViewById(android.R.id.title); + final DocumentInfo doc = getItem(position); + + if (position == 0) { + final RootInfo root = mEnv.getCurrentRoot(); + title.setText(root.title); + subdir.setVisibility(View.GONE); + } else { + title.setText(doc.displayName); + subdir.setVisibility(View.VISIBLE); + } + + return convertView; + } + } + + interface Environment { + RootInfo getCurrentRoot(); + String getDrawerTitle(); + void refreshCurrentRootAndDirectory(int animation); + boolean isSearchExpanded(); + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java index 5dc4f57bdb7b..d6015501b003 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java @@ -19,17 +19,12 @@ package com.android.documentsui; import static android.os.Environment.isStandardDirectory; import static com.android.documentsui.Shared.DEBUG; -import java.io.File; -import java.io.IOException; -import java.util.List; - import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.app.FragmentManager; import android.app.FragmentTransaction; -import android.content.ContentProvider; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; @@ -48,11 +43,15 @@ import android.provider.DocumentsContract; import android.text.TextUtils; import android.util.Log; +import java.io.File; +import java.io.IOException; +import java.util.List; + /** * Activity responsible for handling {@link Intent#ACTION_OPEN_EXTERNAL_DOCUMENT}. */ public class OpenExternalDirectoryActivity extends Activity { - private static final String TAG = "OpenExternalDirectoryActivity"; + private static final String TAG = "OpenExternalDirectory"; private static final String FM_TAG = "open_external_directory"; private static final String EXTERNAL_STORAGE_AUTH = "com.android.externalstorage.documents"; private static final String EXTRA_FILE = "com.android.documentsui.FILE"; @@ -209,7 +208,7 @@ public class OpenExternalDirectoryActivity extends Activity { return intent; } - private static class OpenExternalDirectoryDialogFragment extends DialogFragment { + public static class OpenExternalDirectoryDialogFragment extends DialogFragment { private File mFile; private String mVolumeLabel; diff --git a/packages/DocumentsUI/src/com/android/documentsui/PairedTask.java b/packages/DocumentsUI/src/com/android/documentsui/PairedTask.java new file mode 100644 index 000000000000..b74acb8e38c3 --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/PairedTask.java @@ -0,0 +1,77 @@ +/* + * 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.documentsui; + +import android.app.Activity; +import android.os.AsyncTask; + +/** + * An {@link AsyncTask} that guards work with checks that a paired {@link Activity} + * is still alive. Instances of this class make no progress. + * + * <p>Use this type of task for greater safety when executing tasks that might complete + * after an Activity is destroyed. + * + * <p>Also useful as tasks can be static, limiting scope, but still have access to + * the owning class (by way the A template and the mActivity field). + * + * @template Owner Activity type. + * @template Input input type + * @template Output output type + */ +abstract class PairedTask<Owner extends Activity, Input, Output> + extends AsyncTask<Input, Void, Output> { + + protected final Owner mOwner; + + public PairedTask(Owner owner) { + mOwner = owner; + } + + /** Called prior to run being executed. Analogous to {@link AsyncTask#onPreExecute} */ + void prepare() {} + + /** Analogous to {@link AsyncTask#doInBackground} */ + abstract Output run(Input... input); + + /** Analogous to {@link AsyncTask#onPostExecute} */ + abstract void finish(Output output); + + @Override + final protected void onPreExecute() { + if (mOwner.isDestroyed()) { + return; + } + prepare(); + } + + @Override + final protected Output doInBackground(Input... input) { + if (mOwner.isDestroyed()) { + return null; + } + return run(input); + } + + @Override + final protected void onPostExecute(Output result) { + if (mOwner.isDestroyed()) { + return; + } + finish(result); + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java b/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java new file mode 100644 index 000000000000..9048b9d45ee7 --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java @@ -0,0 +1,52 @@ +/* + * 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.documentsui; + +import android.net.Uri; +import android.provider.DocumentsContract; +import android.util.Log; + +import com.android.documentsui.model.RootInfo; + +final class RestoreRootTask extends PairedTask<BaseActivity, Void, RootInfo> { + private static final String TAG = "RestoreRootTask"; + + private final Uri mRootUri; + + public RestoreRootTask(BaseActivity activity, Uri rootUri) { + super(activity); + mRootUri = rootUri; + } + + @Override + protected RootInfo run(Void... params) { + String rootId = DocumentsContract.getRootId(mRootUri); + return mOwner.mRoots.getRootOneshot(mRootUri.getAuthority(), rootId); + } + + @Override + protected void finish(RootInfo root) { + mOwner.mState.restored = true; + + if (root != null) { + mOwner.onRootPicked(root); + } else { + Log.w(TAG, "Failed to find root: " + mRootUri); + mOwner.finish(); + } + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java index c64953d39b70..26bda31261ef 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java @@ -180,9 +180,9 @@ public class RootsFragment extends Fragment { Item item = mAdapter.getItem(position); if (item instanceof RootItem) { BaseActivity activity = BaseActivity.get(RootsFragment.this); - RootInfo info = ((RootItem) item).root; - Metrics.logRootVisited(getActivity(), info); - activity.onRootPicked(info); + RootInfo newRoot = ((RootItem) item).root; + Metrics.logRootVisited(getActivity(), newRoot); + activity.onRootPicked(newRoot); } else if (item instanceof AppItem) { DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this); ResolveInfo info = ((AppItem) item).info; diff --git a/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java b/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java index fb585a618c47..69f54c77fe8b 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java +++ b/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java @@ -47,7 +47,7 @@ final class SearchManager implements private boolean mSearchExpanded; private boolean mIgnoreNextClose; - private DocumentsToolBar mActionBar; + private DocumentsToolbar mActionBar; private MenuItem mMenu; private SearchView mView; @@ -59,7 +59,7 @@ final class SearchManager implements mListener = listener; } - public void install(DocumentsToolBar actionBar) { + public void install(DocumentsToolbar actionBar) { assert (mActionBar == null); mActionBar = actionBar; mMenu = actionBar.getSearchMenu(); diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java index 5f04eacc086f..70bee3cd3c6e 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -151,7 +151,6 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi private String mStateKey; private int mLastSortOrder = SORT_ORDER_UNKNOWN; - private boolean mLastShowSize; private DocumentsAdapter mAdapter; private LoaderCallbacks<DirectoryResult> mCallbacks; private FragmentTuner mTuner; @@ -428,7 +427,6 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi private void updateDisplayState() { State state = getDisplayState(); - mLastShowSize = state.showSize; updateLayout(state.derivedMode); mRecView.setAdapter(mAdapter); } @@ -855,27 +853,28 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi } private void showEmptyDirectory() { - showEmptyView(R.string.empty); + showEmptyView(R.string.empty, R.drawable.cabinet); } private void showNoResults(RootInfo root) { CharSequence msg = getContext().getResources().getText(R.string.no_results); - showEmptyView(String.format(String.valueOf(msg), root.title)); + showEmptyView(String.format(String.valueOf(msg), root.title), R.drawable.cabinet); } - // Shows an error indicating documents couldn't be queried. private void showQueryError() { - showEmptyView(R.string.query_error); + showEmptyView(R.string.query_error, R.drawable.hourglass); } - private void showEmptyView(@StringRes int id) { - showEmptyView(getContext().getResources().getText(id)); + private void showEmptyView(@StringRes int id, int drawable) { + showEmptyView(getContext().getResources().getText(id), drawable); } - private void showEmptyView(CharSequence msg) { + private void showEmptyView(CharSequence msg, int drawable) { View content = mEmptyView.findViewById(R.id.content); TextView msgView = (TextView) mEmptyView.findViewById(R.id.message); + ImageView imageView = (ImageView) mEmptyView.findViewById(R.id.artwork); msgView.setText(msg); + imageView.setImageResource(drawable); content.animate().cancel(); // cancel any ongoing animations diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java index 880da9c07bef..69a67111ca38 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java @@ -29,7 +29,6 @@ import android.util.SparseArray; import android.view.ViewGroup; import com.android.documentsui.State; - import com.google.common.collect.Sets; import java.util.ArrayList; @@ -42,7 +41,7 @@ import java.util.Set; */ final class ModelBackedDocumentsAdapter extends DocumentsAdapter { - private static final String TAG = "ModelBackedDocumentsAdapter"; + private static final String TAG = "ModelBackedDocuments"; public static final int ITEM_TYPE_DOCUMENT = 1; public static final int ITEM_TYPE_DIRECTORY = 2; diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java index 71708c1f2c5d..0bb682e7c967 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java @@ -44,13 +44,13 @@ import android.widget.TextView.OnEditorActionListener; import com.android.documentsui.BaseActivity; import com.android.documentsui.DocumentsApplication; -import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.R; import com.android.documentsui.Snackbars; +import com.android.documentsui.model.DocumentInfo; /** * Dialog to rename file or directory. */ -class RenameDocumentFragment extends DialogFragment { +public class RenameDocumentFragment extends DialogFragment { private static final String TAG_RENAME_DOCUMENT = "rename_document"; private DocumentInfo mDocument; diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java index 0a91427c6ad9..243c3577500c 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java @@ -30,7 +30,7 @@ import android.support.test.uiautomator.By; import android.support.test.uiautomator.Configurator; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.Until; -import android.test.InstrumentationTestCase; +import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; import android.view.MotionEvent; @@ -38,7 +38,7 @@ import android.view.MotionEvent; import com.android.documentsui.model.RootInfo; @LargeTest -public class DownloadsActivityUiTest extends InstrumentationTestCase { +public class DownloadsActivityUiTest extends ActivityInstrumentationTestCase2<DownloadsActivity> { private static final int TIMEOUT = 5000; private static final String TAG = "DownloadsActivityUiTest"; @@ -53,6 +53,10 @@ public class DownloadsActivityUiTest extends InstrumentationTestCase { private ContentProviderClient mClient; private RootInfo mRoot; + public DownloadsActivityUiTest() { + super(DownloadsActivity.class); + } + public void setUp() throws Exception { // Initialize UiDevice instance. Instrumentation instrumentation = getInstrumentation(); @@ -79,7 +83,8 @@ public class DownloadsActivityUiTest extends InstrumentationTestCase { intent.setDataAndType(mRoot.getUri(), DocumentsContract.Root.MIME_TYPE_ITEM); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - mContext.startActivity(intent); + setActivityIntent(intent); + getActivity(); // Start the activity. // Wait for the app to appear. mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), TIMEOUT); @@ -92,11 +97,11 @@ public class DownloadsActivityUiTest extends InstrumentationTestCase { @Override protected void tearDown() throws Exception { - // Need to kill off the task we started. - super.tearDown(); Log.d(TAG, "Resetting storage from setUp"); resetStorage(); mClient.release(); + + super.tearDown(); } private void resetStorage() throws RemoteException { diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java index 2535a80eb37e..868dbbb39e1b 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java @@ -30,7 +30,7 @@ import android.support.test.uiautomator.By; import android.support.test.uiautomator.Configurator; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.Until; -import android.test.InstrumentationTestCase; +import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; import android.view.MotionEvent; @@ -38,7 +38,7 @@ import android.view.MotionEvent; import com.android.documentsui.model.RootInfo; @LargeTest -public class FilesActivityUiTest extends InstrumentationTestCase { +public class FilesActivityUiTest extends ActivityInstrumentationTestCase2<FilesActivity> { private static final int TIMEOUT = 5000; private static final String TAG = "FilesActivityUiTest"; @@ -54,6 +54,10 @@ public class FilesActivityUiTest extends InstrumentationTestCase { private RootInfo mRoot_0; private RootInfo mRoot_1; + public FilesActivityUiTest() { + super(FilesActivity.class); + } + public void setUp() throws Exception { // Initialize UiDevice instance. Instrumentation instrumentation = getInstrumentation(); @@ -71,12 +75,14 @@ public class FilesActivityUiTest extends InstrumentationTestCase { mResolver = mContext.getContentResolver(); mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY); + assertNotNull("Failed to acquire ContentProviderClient.", mClient); mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient); // Launch app. Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(TARGET_PKG); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - mContext.startActivity(intent); + setActivityIntent(intent); + getActivity(); // Start the activity. // Wait for the app to appear. mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), TIMEOUT); @@ -89,10 +95,11 @@ public class FilesActivityUiTest extends InstrumentationTestCase { @Override protected void tearDown() throws Exception { - super.tearDown(); Log.d(TAG, "Resetting storage from setUp"); resetStorage(); mClient.release(); + + super.tearDown(); } private void resetStorage() throws RemoteException { diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java index 98554276e71c..25276505ee43 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java @@ -16,10 +16,6 @@ package com.android.documentsui; -import static com.android.documentsui.Shared.TAG; - -import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ProviderInfo; @@ -471,6 +467,14 @@ public class StubProvider extends DocumentsProvider { @Override public Bundle call(String method, String arg, Bundle extras) { + // We're not supposed to override any of the default DocumentsProvider + // methods that are supported by "call", so javadoc asks that we + // always call super.call first and return if response is not null. + Bundle result = super.call(method, arg, extras); + if (result != null) { + return result; + } + switch (method) { case "clear": clearCacheAndBuildRoots(); @@ -484,11 +488,10 @@ public class StubProvider extends DocumentsProvider { simulateReadErrorsForFile(arg); return null; case "createDocumentWithFlags": - Bundle bundle = dispatchCreateDocumentWithFlags(extras); - return bundle; - default: - return super.call(method, arg, extras); + return dispatchCreateDocumentWithFlags(extras); } + + return null; } private Bundle createVirtualFileFromBundle(Bundle extras) { diff --git a/packages/ExtServices/Android.mk b/packages/ExtServices/Android.mk new file mode 100644 index 000000000000..e8a40078ef0f --- /dev/null +++ b/packages/ExtServices/Android.mk @@ -0,0 +1,40 @@ +# 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := ExtServices + +LOCAL_CERTIFICATE := platform + +LOCAL_AAPT_FLAGS := --shared-lib + +LOCAL_EXPORT_PACKAGE_RESOURCES := true + +LOCAL_PROGUARD_FLAG_FILES := proguard.proguard + +LOCAL_PRIVILEGED_MODULE := true + +include $(BUILD_PACKAGE) + + + + + diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml new file mode 100644 index 000000000000..100b35c13d34 --- /dev/null +++ b/packages/ExtServices/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.ext.services" + android:versionCode="1" + android:versionName="1" + coreApp="true"> + + <application android:label="@string/app_name" + android:allowBackup="false" + android:forceDeviceEncrypted="true" + android:encryptionAware="true"> + + <library android:name="android.ext.services"/> + + </application> + +</manifest> diff --git a/packages/ExtServices/MODULE_LICENSE_APACHE2 b/packages/ExtServices/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/packages/ExtServices/MODULE_LICENSE_APACHE2 diff --git a/packages/ExtServices/NOTICE b/packages/ExtServices/NOTICE new file mode 100644 index 000000000000..c5b1efa7aac7 --- /dev/null +++ b/packages/ExtServices/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/packages/ExtServices/proguard.proguard b/packages/ExtServices/proguard.proguard new file mode 100644 index 000000000000..e5dfbe1c453d --- /dev/null +++ b/packages/ExtServices/proguard.proguard @@ -0,0 +1,7 @@ +-keepparameternames +-keepattributes Exceptions,InnerClasses,Signature,Deprecated, + SourceFile,LineNumberTable,*Annotation*,EnclosingMethod + +-keep public class * { + public protected *; +} diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml new file mode 100644 index 000000000000..531e5171dec8 --- /dev/null +++ b/packages/ExtServices/res/values/strings.xml @@ -0,0 +1,19 @@ +<?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. +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name">Android Services Library</string> +</resources> diff --git a/packages/ExtServices/src/android/ext/services/Version.java b/packages/ExtServices/src/android/ext/services/Version.java new file mode 100644 index 000000000000..026cccd37334 --- /dev/null +++ b/packages/ExtServices/src/android/ext/services/Version.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.ext.services; + +/** + * Class that provides the version of the library. + */ +public final class Version { + + private Version() { + /* do nothing - hide constructor */ + } + + /** + * Gets the version of the library. + * + * @return The version. + */ + public static int getVersionCode() { + return 1; + } +}
\ No newline at end of file diff --git a/packages/ExtShared/Android.mk b/packages/ExtShared/Android.mk new file mode 100644 index 000000000000..d8052df8a8e8 --- /dev/null +++ b/packages/ExtShared/Android.mk @@ -0,0 +1,33 @@ +# 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := ExtShared + +LOCAL_CERTIFICATE := platform + +LOCAL_AAPT_FLAGS := --shared-lib + +LOCAL_EXPORT_PACKAGE_RESOURCES := true + +LOCAL_PROGUARD_FLAG_FILES := proguard.proguard + +include $(BUILD_PACKAGE)
\ No newline at end of file diff --git a/packages/ExtShared/AndroidManifest.xml b/packages/ExtShared/AndroidManifest.xml new file mode 100644 index 000000000000..e2e81d08c747 --- /dev/null +++ b/packages/ExtShared/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.ext.shared" + android:versionCode="1" + android:versionName="1" + coreApp="true"> + + <application android:label="@string/app_name" + android:allowBackup="false" + android:forceDeviceEncrypted="true" + android:encryptionAware="true"> + + <library android:name="android.ext.shared"/> + + </application> + +</manifest> diff --git a/packages/ExtShared/MODULE_LICENSE_APACHE2 b/packages/ExtShared/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/packages/ExtShared/MODULE_LICENSE_APACHE2 diff --git a/packages/ExtShared/NOTICE b/packages/ExtShared/NOTICE new file mode 100644 index 000000000000..c5b1efa7aac7 --- /dev/null +++ b/packages/ExtShared/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/packages/ExtShared/proguard.proguard b/packages/ExtShared/proguard.proguard new file mode 100644 index 000000000000..e5dfbe1c453d --- /dev/null +++ b/packages/ExtShared/proguard.proguard @@ -0,0 +1,7 @@ +-keepparameternames +-keepattributes Exceptions,InnerClasses,Signature,Deprecated, + SourceFile,LineNumberTable,*Annotation*,EnclosingMethod + +-keep public class * { + public protected *; +} diff --git a/packages/ExtShared/res/values/strings.xml b/packages/ExtShared/res/values/strings.xml new file mode 100644 index 000000000000..0914e4318bce --- /dev/null +++ b/packages/ExtShared/res/values/strings.xml @@ -0,0 +1,19 @@ +<?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. +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_name">Android Shared Library</string> +</resources> diff --git a/packages/ExtShared/src/android/ext/shared/Version.java b/packages/ExtShared/src/android/ext/shared/Version.java new file mode 100644 index 000000000000..3ff2d415bc20 --- /dev/null +++ b/packages/ExtShared/src/android/ext/shared/Version.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.ext.shared; + +/** + * Class that provides the version of the library. + */ +public final class Version { + + private Version() { + /* do nothing - hide constructor */ + } + + /** + * Gets the version of the library. + * + * @return The version. + */ + public static int getVersionCode() { + return 1; + } +}
\ No newline at end of file diff --git a/packages/MtpDocumentsProvider/AndroidManifest.xml b/packages/MtpDocumentsProvider/AndroidManifest.xml index 7ea54c9774bf..2dd49ab0782f 100644 --- a/packages/MtpDocumentsProvider/AndroidManifest.xml +++ b/packages/MtpDocumentsProvider/AndroidManifest.xml @@ -30,16 +30,12 @@ </activity> <receiver android:name=".UsbIntentReceiver" android:exported="true"> - <!-- TODO: Remove an intent-filter for USB_DEVICE_ATTACHED after the provider becomes to - open devices on demand. --> <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> + <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" /> - <intent-filter> - <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" /> - </intent-filter> </receiver> </application> </manifest> diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java index 1829746bb143..ef1e8e20aaff 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java @@ -24,9 +24,11 @@ import android.net.Uri; import android.os.Bundle; import android.os.Process; import android.provider.DocumentsContract; +import android.util.Log; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.LinkedList; @@ -56,11 +58,17 @@ class DocumentLoader { private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles) throws IOException { - final MtpObjectInfo[] objectInfos = new MtpObjectInfo[handles.length]; + final ArrayList<MtpObjectInfo> objects = new ArrayList<>(); for (int i = 0; i < handles.length; i++) { - objectInfos[i] = manager.getObjectInfo(deviceId, handles[i]); + final MtpObjectInfo info = manager.getObjectInfo(deviceId, handles[i]); + if (info == null) { + Log.e(MtpDocumentsProvider.TAG, + "Failed to obtain object info handle=" + handles[i]); + continue; + } + objects.add(info); } - return objectInfos; + return objects.toArray(new MtpObjectInfo[objects.size()]); } synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent) diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java index 76a1fad30442..124d207696aa 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java @@ -44,11 +44,38 @@ class Identifier { return false; final Identifier other = (Identifier) obj; return mDeviceId == other.mDeviceId && mStorageId == other.mStorageId && - mObjectHandle == other.mObjectHandle && mDocumentId == other.mDocumentId; + mObjectHandle == other.mObjectHandle && mDocumentId.equals(other.mDocumentId); } @Override public int hashCode() { return Objects.hash(mDeviceId, mStorageId, mObjectHandle, mDocumentId); } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("Identifier { "); + + builder.append("mDeviceId: "); + builder.append(mDeviceId); + builder.append(", "); + + builder.append("mStorageId: "); + builder.append(mStorageId); + builder.append(", "); + + builder.append("mObjectHandle: "); + builder.append(mObjectHandle); + builder.append(", "); + + builder.append("mDocumentId: "); + builder.append(mDocumentId); + builder.append(", "); + + builder.append("mDocumentType: "); + builder.append(mDocumentType); + builder.append(" }"); + return builder.toString(); + } } diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java index ac470671a582..3faa8f4394f7 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java @@ -20,11 +20,9 @@ import static com.android.mtp.MtpDatabaseConstants.*; import android.annotation.Nullable; import android.content.ContentValues; -import android.content.res.Resources; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; import android.mtp.MtpObjectInfo; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; @@ -87,12 +85,10 @@ class Mapper { /** * Puts root information to database. * @param parentDocumentId Document ID of device document. - * @param resources Resources required to localize root name. * @param roots List of root information. * @return If roots are added or removed from the database. */ - synchronized boolean putStorageDocuments( - String parentDocumentId, Resources resources, MtpRoot[] roots) { + synchronized boolean putStorageDocuments(String parentDocumentId, MtpRoot[] roots) { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); database.beginTransaction(); try { @@ -117,7 +113,7 @@ class Mapper { valuesList[i] = new ContentValues(); extraValuesList[i] = new ContentValues(); MtpDatabase.getStorageDocumentValues( - valuesList[i], extraValuesList[i], resources, parentDocumentId, roots[i]); + valuesList[i], extraValuesList[i], parentDocumentId, roots[i]); } final boolean changed = putDocuments( valuesList, diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java index 59d85c1ef8f4..8a3ebefa127f 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java @@ -108,7 +108,7 @@ class MtpDatabase { * @param columnNames Column names defined in {@link android.provider.DocumentsContract.Root}. * @return Database cursor. */ - Cursor queryRoots(String[] columnNames) { + Cursor queryRoots(Resources resources, String[] columnNames) { final String selection = COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?"; final Cursor deviceCursor = mDatabase.query( @@ -183,10 +183,14 @@ class MtpDatabase { } if (storageCursor.getCount() == 1 && values.containsKey(Root.COLUMN_TITLE)) { storageCursor.moveToFirst(); + // Add storage name to device name if we have only 1 storage. values.put( Root.COLUMN_TITLE, - storageCursor.getString( - storageCursor.getColumnIndex(Root.COLUMN_TITLE))); + resources.getString( + R.string.root_name, + values.getAsString(Root.COLUMN_TITLE), + storageCursor.getString( + storageCursor.getColumnIndex(Root.COLUMN_TITLE)))); } } finally { storageCursor.close(); @@ -533,13 +537,11 @@ class MtpDatabase { /** * Gets {@link ContentValues} for the given root. * @param values {@link ContentValues} that receives values. - * @param resources Resources used to get localized root name. * @param root Root to be converted {@link ContentValues}. */ static void getStorageDocumentValues( ContentValues values, ContentValues extraValues, - Resources resources, String parentDocumentId, MtpRoot root) { values.clear(); @@ -550,13 +552,12 @@ class MtpDatabase { values.put(COLUMN_ROW_STATE, ROW_STATE_VALID); values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_STORAGE); values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); - values.put(Document.COLUMN_DISPLAY_NAME, root.getRootName(resources)); + values.put(Document.COLUMN_DISPLAY_NAME, root.mDescription); values.putNull(Document.COLUMN_SUMMARY); values.putNull(Document.COLUMN_LAST_MODIFIED); values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp); values.put(Document.COLUMN_FLAGS, 0); - values.put(Document.COLUMN_SIZE, - (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE)); + values.put(Document.COLUMN_SIZE, root.mMaxCapacity - root.mFreeSpace); extraValues.put( Root.COLUMN_FLAGS, @@ -576,9 +577,7 @@ class MtpDatabase { static void getObjectDocumentValues( ContentValues values, int deviceId, String parentId, MtpObjectInfo info) { values.clear(); - final String mimeType = info.getFormat() == MtpConstants.FORMAT_ASSOCIATION ? - DocumentsContract.Document.MIME_TYPE_DIR : - MediaFile.getMimeTypeForFormatCode(info.getFormat()); + final String mimeType = getMimeType(info); int flag = 0; if (info.getProtectionStatus() == 0) { flag |= Document.FLAG_SUPPORTS_DELETE | @@ -607,6 +606,17 @@ class MtpDatabase { values.put(Document.COLUMN_SIZE, info.getCompressedSize()); } + private static String getMimeType(MtpObjectInfo info) { + if (info.getFormat() == MtpConstants.FORMAT_ASSOCIATION) { + return DocumentsContract.Document.MIME_TYPE_DIR; + } + final String formatCodeMimeType = MediaFile.getMimeTypeForFormatCode(info.getFormat()); + if (formatCodeMimeType != null) { + return formatCodeMimeType; + } + return MediaFile.getMimeTypeForFile(info.getName()); + } + static String[] strings(Object... args) { final String[] results = new String[args.length]; for (int i = 0; i < args.length; i++) { diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java index 775f9766e249..033845401b4b 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java @@ -58,6 +58,8 @@ public class MtpDocumentsProvider extends DocumentsProvider { Document.COLUMN_FLAGS, Document.COLUMN_SIZE, }; + static final boolean DEBUG = false; + private final Object mDeviceListLock = new Object(); private static MtpDocumentsProvider sSingleton; @@ -70,6 +72,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { private Resources mResources; private MtpDatabase mDatabase; private AppFuse mAppFuse; + private ServiceIntentSender mIntentSender; /** * Provides singleton instance to MtpDocumentsService. @@ -86,8 +89,9 @@ public class MtpDocumentsProvider extends DocumentsProvider { mResolver = getContext().getContentResolver(); mDeviceToolkits = new HashMap<Integer, DeviceToolkit>(); mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_FILE); - mRootScanner = new RootScanner(mResolver, mResources, mMtpManager, mDatabase); + mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase); mAppFuse = new AppFuse(TAG, new AppFuseCallback()); + mIntentSender = new ServiceIntentSender(getContext()); // TODO: Mount AppFuse on demands. try { mAppFuse.mount(getContext().getSystemService(StorageManager.class)); @@ -105,14 +109,16 @@ public class MtpDocumentsProvider extends DocumentsProvider { MtpManager mtpManager, ContentResolver resolver, MtpDatabase database, - StorageManager storageManager) { + StorageManager storageManager, + ServiceIntentSender intentSender) { mResources = resources; mMtpManager = mtpManager; mResolver = resolver; mDeviceToolkits = new HashMap<Integer, DeviceToolkit>(); mDatabase = database; - mRootScanner = new RootScanner(mResolver, mResources, mMtpManager, mDatabase); + mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase); mAppFuse = new AppFuse(TAG, new AppFuseCallback()); + mIntentSender = intentSender; // TODO: Mount AppFuse on demands. try { mAppFuse.mount(storageManager); @@ -129,7 +135,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { if (projection == null) { projection = MtpDocumentsProvider.DEFAULT_ROOT_PROJECTION; } - final Cursor cursor = mDatabase.queryRoots(projection); + final Cursor cursor = mDatabase.queryRoots(mResources, projection); cursor.setNotificationUri( mResolver, DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY)); return cursor; @@ -147,11 +153,15 @@ public class MtpDocumentsProvider extends DocumentsProvider { @Override public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException { + if (DEBUG) { + Log.d(TAG, "queryChildDocuments: " + parentDocumentId); + } if (projection == null) { projection = MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION; } Identifier parentIdentifier = mDatabase.createIdentifier(parentDocumentId); try { + openDevice(parentIdentifier.mDeviceId); if (parentIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) { final Identifier singleStorageIdentifier = mDatabase.getSingleStorageIdentifier(parentDocumentId); @@ -174,13 +184,17 @@ public class MtpDocumentsProvider extends DocumentsProvider { public ParcelFileDescriptor openDocument( String documentId, String mode, CancellationSignal signal) throws FileNotFoundException { + if (DEBUG) { + Log.d(TAG, "openDocument: " + documentId); + } final Identifier identifier = mDatabase.createIdentifier(documentId); try { + openDevice(identifier.mDeviceId); switch (mode) { case "r": final long fileSize = getFileSize(documentId); - // MTP getPartialObject operation does not support files that are larger than 4GB. - // Fallback to non-seekable file descriptor. + // MTP getPartialObject operation does not support files that are larger than + // 4GB. Fallback to non-seekable file descriptor. // TODO: Use getPartialObject64 for MTP devices that support Android vendor // extension. if (fileSize <= 0xffffffffl) { @@ -213,6 +227,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { CancellationSignal signal) throws FileNotFoundException { final Identifier identifier = mDatabase.createIdentifier(documentId); try { + openDevice(identifier.mDeviceId); return new AssetFileDescriptor( getPipeManager(identifier).readThumbnail(mMtpManager, identifier), 0, // Start offset. @@ -227,6 +242,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { public void deleteDocument(String documentId) throws FileNotFoundException { try { final Identifier identifier = mDatabase.createIdentifier(documentId); + openDevice(identifier.mDeviceId); final Identifier parentIdentifier = mDatabase.getParentIdentifier(documentId); mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle); mDatabase.deleteDocument(documentId); @@ -257,8 +273,12 @@ public class MtpDocumentsProvider extends DocumentsProvider { @Override public String createDocument(String parentDocumentId, String mimeType, String displayName) throws FileNotFoundException { + if (DEBUG) { + Log.d(TAG, "createDocument: " + displayName); + } try { final Identifier parentId = mDatabase.createIdentifier(parentDocumentId); + openDevice(parentId.mDeviceId); final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe(); pipe[0].close(); // 0 bytes for a new document. final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ? @@ -286,11 +306,22 @@ public class MtpDocumentsProvider extends DocumentsProvider { void openDevice(int deviceId) throws IOException { synchronized (mDeviceListLock) { + if (mDeviceToolkits.containsKey(deviceId)) { + return; + } + if (DEBUG) { + Log.d(TAG, "Open device " + deviceId); + } mMtpManager.openDevice(deviceId); mDeviceToolkits.put( deviceId, new DeviceToolkit(mMtpManager, mResolver, mDatabase)); + mIntentSender.sendUpdateNotificationIntent(); + try { + mRootScanner.resume().await(); + } catch (InterruptedException error) { + Log.e(TAG, "openDevice", error); + } } - mRootScanner.resume(); } void closeDevice(int deviceId) throws IOException, InterruptedException { @@ -298,6 +329,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { closeDeviceInternal(deviceId); } mRootScanner.resume(); + mIntentSender.sendUpdateNotificationIntent(); } int[] getOpenedDeviceIds() { @@ -318,6 +350,13 @@ public class MtpDocumentsProvider extends DocumentsProvider { } /** + * Resumes root scanner to handle the update of device list. + */ + void resumeRootScanner() { + mRootScanner.resume(); + } + + /** * Finalize the content provider for unit tests. */ @Override @@ -356,6 +395,12 @@ public class MtpDocumentsProvider extends DocumentsProvider { private void closeDeviceInternal(int deviceId) throws IOException, InterruptedException { // TODO: Flush the device before closing (if not closed externally). + if (!mDeviceToolkits.containsKey(deviceId)) { + return; + } + if (DEBUG) { + Log.d(TAG, "Close device " + deviceId); + } getDeviceToolkit(deviceId).mDocumentLoader.clearTasks(); mDeviceToolkits.remove(deviceId); mMtpManager.closeDevice(deviceId); diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java index 5bede8617d60..9c4952bc5759 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java @@ -19,13 +19,12 @@ package com.android.mtp; import android.app.Notification; import android.app.Service; import android.app.NotificationManager; +import android.content.ComponentName; +import android.content.Context; import android.content.Intent; -import android.hardware.usb.UsbDevice; import android.os.IBinder; import android.util.Log; -import com.android.internal.util.Preconditions; - import java.io.IOException; /** @@ -36,6 +35,7 @@ import java.io.IOException; public class MtpDocumentsService extends Service { static final String ACTION_OPEN_DEVICE = "com.android.mtp.OPEN_DEVICE"; static final String ACTION_CLOSE_DEVICE = "com.android.mtp.CLOSE_DEVICE"; + static final String ACTION_UPDATE_NOTIFICATION = "com.android.mtp.UPDATE_NOTIFICATION"; static final String EXTRA_DEVICE = "device"; NotificationManager mNotificationManager; @@ -55,32 +55,10 @@ public class MtpDocumentsService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { // If intent is null, the service was restarted. - if (intent != null) { - final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance(); - final UsbDevice device = intent.<UsbDevice>getParcelableExtra(EXTRA_DEVICE); - try { - Preconditions.checkNotNull(device); - switch (intent.getAction()) { - case ACTION_OPEN_DEVICE: - provider.openDevice(device.getDeviceId()); - break; - - case ACTION_CLOSE_DEVICE: - mNotificationManager.cancel(device.getDeviceId()); - provider.closeDevice(device.getDeviceId()); - break; - - default: - throw new IllegalArgumentException("Received unknown intent action."); - } - } catch (IOException | InterruptedException | IllegalArgumentException error) { - logErrorMessage(error); - } - } else { - // TODO: Fetch devices again. + if (intent == null || ACTION_UPDATE_NOTIFICATION.equals(intent.getAction())) { + return updateForegroundState() ? START_STICKY : START_NOT_STICKY; } - - return updateForegroundState() ? START_STICKY : START_NOT_STICKY; + return START_NOT_STICKY; } /** @@ -92,6 +70,7 @@ public class MtpDocumentsService extends Service { final int[] deviceIds = provider.getOpenedDeviceIds(); int notificationId = 0; Notification notification = null; + // TODO: Hide notification if the device has already been removed. for (final int deviceId : deviceIds) { try { final String title = getResources().getString( diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java index efe5ff172d78..5519efd5a323 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java @@ -273,9 +273,7 @@ class MtpManager { final MtpRoot[] results = new MtpRoot[storageIds.length]; for (int i = 0; i < storageIds.length; i++) { results[i] = new MtpRoot( - device.getDeviceId(), - device.getDeviceInfo().getModel(), - device.getStorageInfo(storageIds[i])); + device.getDeviceId(), device.getStorageInfo(storageIds[i])); } return results; } diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpRoot.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpRoot.java index ec338c33bc7b..8530aaff7f95 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpRoot.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpRoot.java @@ -16,7 +16,6 @@ package com.android.mtp; -import android.content.res.Resources; import android.mtp.MtpStorageInfo; import com.android.internal.annotations.VisibleForTesting; @@ -24,7 +23,6 @@ import com.android.internal.annotations.VisibleForTesting; class MtpRoot { final int mDeviceId; final int mStorageId; - final String mDeviceModelName; final String mDescription; final long mFreeSpace; final long mMaxCapacity; @@ -33,24 +31,21 @@ class MtpRoot { @VisibleForTesting MtpRoot(int deviceId, int storageId, - String deviceName, String description, long freeSpace, long maxCapacity, String volumeIdentifier) { mDeviceId = deviceId; mStorageId = storageId; - mDeviceModelName = deviceName; mDescription = description; mFreeSpace = freeSpace; mMaxCapacity = maxCapacity; mVolumeIdentifier = volumeIdentifier; } - MtpRoot(int deviceId, String deviceModelName, MtpStorageInfo storageInfo) { + MtpRoot(int deviceId, MtpStorageInfo storageInfo) { mDeviceId = deviceId; mStorageId = storageInfo.getStorageId(); - mDeviceModelName = deviceModelName; mDescription = storageInfo.getDescription(); mFreeSpace = storageInfo.getFreeSpace(); mMaxCapacity = storageInfo.getMaxCapacity(); @@ -64,7 +59,6 @@ class MtpRoot { final MtpRoot other = (MtpRoot) object; return mDeviceId == other.mDeviceId && mStorageId == other.mStorageId && - mDeviceModelName.equals(other.mDeviceModelName) && mDescription.equals(other.mDescription) && mFreeSpace == other.mFreeSpace && mMaxCapacity == other.mMaxCapacity && @@ -73,19 +67,12 @@ class MtpRoot { @Override public int hashCode() { - return mDeviceId ^ mStorageId ^ mDeviceModelName.hashCode() ^ mDescription.hashCode() ^ + return mDeviceId ^ mStorageId ^ mDescription.hashCode() ^ ((int) mFreeSpace) ^ ((int) mMaxCapacity) ^ mVolumeIdentifier.hashCode(); } - + @Override public String toString() { - return "MtpRoot{Name: " + mDeviceModelName + " " + mDescription + "}"; - } - - String getRootName(Resources resources) { - return String.format( - resources.getString(R.string.root_name), - mDeviceModelName, - mDescription); + return "MtpRoot{Name: " + mDescription + "}"; } } diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java index 15b8ef3cae9a..a4c3cf4fa5b4 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java @@ -1,12 +1,28 @@ +/* + * 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.mtp; import android.content.ContentResolver; -import android.content.res.Resources; import android.net.Uri; import android.os.Process; import android.provider.DocumentsContract; import android.util.Log; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; @@ -35,7 +51,6 @@ final class RootScanner { private final static long AWAIT_TERMINATION_TIMEOUT = 2000; final ContentResolver mResolver; - final Resources mResources; final MtpManager mManager; final MtpDatabase mDatabase; @@ -44,11 +59,9 @@ final class RootScanner { RootScanner( ContentResolver resolver, - Resources resources, MtpManager manager, MtpDatabase database) { mResolver = resolver; - mResources = resources; mManager = manager; mDatabase = database; } @@ -64,9 +77,8 @@ final class RootScanner { /** * Starts to check new changes right away. - * If the background thread has already gone, it restarts another background thread. */ - synchronized void resume() { + synchronized CountDownLatch resume() { if (mExecutor == null) { // Only single thread updates the database. mExecutor = Executors.newSingleThreadExecutor(); @@ -75,8 +87,10 @@ final class RootScanner { // Cancel previous task. mCurrentTask.cancel(true); } - mCurrentTask = new FutureTask<Void>(new UpdateRootsRunnable(), null); + final UpdateRootsRunnable runnable = new UpdateRootsRunnable(); + mCurrentTask = new FutureTask<Void>(runnable, null); mExecutor.submit(mCurrentTask); + return runnable.mFirstScanCompleted; } /** @@ -98,6 +112,8 @@ final class RootScanner { * Runnable to scan roots and update the database information. */ private final class UpdateRootsRunnable implements Runnable { + final CountDownLatch mFirstScanCompleted = new CountDownLatch(1); + @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); @@ -124,8 +140,7 @@ final class RootScanner { continue; } mDatabase.getMapper().startAddingDocuments(documentId); - if (mDatabase.getMapper().putStorageDocuments( - documentId, mResources, device.roots)) { + if (mDatabase.getMapper().putStorageDocuments(documentId, device.roots)) { changed = true; } if (mDatabase.getMapper().stopAddingDocuments(documentId)) { @@ -136,6 +151,7 @@ final class RootScanner { if (changed) { notifyChange(); } + mFirstScanCompleted.countDown(); pollingCount++; try { // Use SHORT_POLLING_PERIOD for the first SHORT_POLLING_TIMES because it is diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java b/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java new file mode 100644 index 000000000000..a1bb2c13d386 --- /dev/null +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java @@ -0,0 +1,38 @@ +/* + * 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.mtp; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; + +/** + * Sends intent to MtpDocumentsService. + */ +class ServiceIntentSender { + private Context mContext; + + ServiceIntentSender(Context context) { + mContext = context; + } + + void sendUpdateNotificationIntent() { + final Intent intent = new Intent(MtpDocumentsService.ACTION_UPDATE_NOTIFICATION); + intent.setComponent(new ComponentName(mContext, MtpDocumentsService.class)); + mContext.startService(intent); + } +} diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/UsbIntentReceiver.java b/packages/MtpDocumentsProvider/src/com/android/mtp/UsbIntentReceiver.java index 0ac130eb7ec0..0489ea863396 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/UsbIntentReceiver.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/UsbIntentReceiver.java @@ -21,7 +21,9 @@ import android.content.Context; import android.content.Intent; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; -import android.net.Uri; +import android.util.Log; + +import java.io.IOException; public class UsbIntentReceiver extends BroadcastReceiver { @Override @@ -29,17 +31,15 @@ public class UsbIntentReceiver extends BroadcastReceiver { final UsbDevice device = intent.getExtras().getParcelable(UsbManager.EXTRA_DEVICE); switch (intent.getAction()) { case UsbManager.ACTION_USB_DEVICE_ATTACHED: - startService(context, MtpDocumentsService.ACTION_OPEN_DEVICE, device); + MtpDocumentsProvider.getInstance().resumeRootScanner(); break; case UsbManager.ACTION_USB_DEVICE_DETACHED: - startService(context, MtpDocumentsService.ACTION_CLOSE_DEVICE, device); + try { + MtpDocumentsProvider.getInstance().closeDevice(device.getDeviceId()); + } catch (IOException | InterruptedException e) { + Log.e(MtpDocumentsProvider.TAG, "Failed to close device", e); + } break; } } - - private void startService(Context context, String action, UsbDevice device) { - final Intent intent = new Intent(action, Uri.EMPTY, context, MtpDocumentsService.class); - intent.putExtra(MtpDocumentsService.EXTRA_DEVICE, device); - context.startService(intent); - } } diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java index 5f71606dffc5..af1fed49f272 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java @@ -42,8 +42,8 @@ public class DocumentLoaderTest extends AndroidTestCase { public void setUp() { mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); mDatabase.getMapper().startAddingDocuments("deviceDocId"); - mDatabase.getMapper().putStorageDocuments("deviceDocId", new TestResources(), new MtpRoot[] { - new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") + mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] { + new MtpRoot(0, 0, "Storage", 1000, 1000, "") }); mDatabase.getMapper().stopAddingDocuments("deviceDocId"); mManager = new BlockableTestMtpManager(getContext()); diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java index 40228864d4fb..a49dc6784af4 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java @@ -81,8 +81,8 @@ public class MtpDatabaseTest extends AndroidTestCase { mDatabase.getMapper().stopAddingDocuments(null); mDatabase.getMapper().startAddingDocuments("1"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 1, "Device", "Storage", 1000, 2000, "") + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 1, "Storage", 1000, 2000, "") }); mDatabase.getMapper().stopAddingDocuments("1"); @@ -96,7 +96,7 @@ public class MtpDatabaseTest extends AndroidTestCase { assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID)); assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE)); assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE)); - assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); assertTrue(isNull(cursor, COLUMN_SUMMARY)); assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED)); assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON)); @@ -109,7 +109,7 @@ public class MtpDatabaseTest extends AndroidTestCase { } { - final Cursor cursor = mDatabase.queryRoots(new String [] { + final Cursor cursor = mDatabase.queryRoots(resources, new String [] { Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, @@ -139,10 +139,10 @@ public class MtpDatabaseTest extends AndroidTestCase { public void testPutStorageDocuments() throws Exception { mDatabase.getMapper().startAddingDocuments("deviceDocId"); - mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] { - new MtpRoot(0, 1, "Device", "Storage", 1000, 2000, ""), - new MtpRoot(0, 2, "Device", "Storage", 2000, 4000, ""), - new MtpRoot(0, 3, "Device", "/@#%&<>Storage", 3000, 6000,"") + mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] { + new MtpRoot(0, 1, "Storage", 1000, 2000, ""), + new MtpRoot(0, 2, "Storage", 2000, 4000, ""), + new MtpRoot(0, 3, "/@#%&<>Storage", 3000, 6000,"") }); { @@ -155,7 +155,7 @@ public class MtpDatabaseTest extends AndroidTestCase { assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID)); assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE)); assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE)); - assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); assertTrue(isNull(cursor, COLUMN_SUMMARY)); assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED)); assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON)); @@ -166,11 +166,11 @@ public class MtpDatabaseTest extends AndroidTestCase { cursor.moveToNext(); assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); - assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.moveToNext(); assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); - assertEquals("Device /@#%&<>Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("/@#%&<>Storage", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.close(); } @@ -264,9 +264,9 @@ public class MtpDatabaseTest extends AndroidTestCase { }; mDatabase.getMapper().startAddingDocuments("deviceDocId"); - mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage A", 1000, 0, ""), - new MtpRoot(0, 101, "Device", "Storage B", 1001, 0, "") + mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] { + new MtpRoot(0, 100, "Storage A", 1000, 0, ""), + new MtpRoot(0, 101, "Storage B", 1001, 0, "") }); { @@ -275,11 +275,11 @@ public class MtpDatabaseTest extends AndroidTestCase { cursor.moveToNext(); assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage A", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.moveToNext(); assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(101, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage B", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.close(); } @@ -291,18 +291,18 @@ public class MtpDatabaseTest extends AndroidTestCase { cursor.moveToNext(); assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID)); assertTrue(isNull(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage A", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.moveToNext(); assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); assertTrue(isNull(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage B", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.close(); } mDatabase.getMapper().startAddingDocuments("deviceDocId"); - mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] { - new MtpRoot(0, 200, "Device", "Storage A", 2000, 0, ""), - new MtpRoot(0, 202, "Device", "Storage C", 2002, 0, "") + mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] { + new MtpRoot(0, 200, "Storage A", 2000, 0, ""), + new MtpRoot(0, 202, "Storage C", 2002, 0, "") }); { @@ -311,15 +311,15 @@ public class MtpDatabaseTest extends AndroidTestCase { cursor.moveToNext(); assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID)); assertTrue(isNull(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage A", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.moveToNext(); assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); assertTrue(isNull(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage B", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.moveToNext(); assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(202, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage C", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage C", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.close(); } @@ -331,11 +331,11 @@ public class MtpDatabaseTest extends AndroidTestCase { cursor.moveToNext(); assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage A", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.moveToNext(); assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(202, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage C", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage C", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.close(); } } @@ -432,11 +432,11 @@ public class MtpDatabaseTest extends AndroidTestCase { mDatabase.getMapper().startAddingDocuments("1"); mDatabase.getMapper().startAddingDocuments("2"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device A", "Storage", 0, 0, "") + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 100, "Storage", 0, 0, "") }); - mDatabase.getMapper().putStorageDocuments("2", resources, new MtpRoot[] { - new MtpRoot(1, 100, "Device B", "Storage", 0, 0, "") + mDatabase.getMapper().putStorageDocuments("2", new MtpRoot[] { + new MtpRoot(1, 100, "Storage", 0, 0, "") }); { @@ -445,16 +445,16 @@ public class MtpDatabaseTest extends AndroidTestCase { cursor.moveToNext(); assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device A Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.moveToNext(); assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device B Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.close(); } { - final Cursor cursor = mDatabase.queryRoots(rootColumns); + final Cursor cursor = mDatabase.queryRoots(resources, rootColumns); assertEquals(2, cursor.getCount()); cursor.moveToNext(); assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID)); @@ -469,11 +469,11 @@ public class MtpDatabaseTest extends AndroidTestCase { mDatabase.getMapper().startAddingDocuments("1"); mDatabase.getMapper().startAddingDocuments("2"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 200, "Device", "Storage", 2000, 0, "") + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 200, "Storage", 2000, 0, "") }); - mDatabase.getMapper().putStorageDocuments("2", resources, new MtpRoot[] { - new MtpRoot(1, 300, "Device", "Storage", 3000, 0, "") + mDatabase.getMapper().putStorageDocuments("2", new MtpRoot[] { + new MtpRoot(1, 300, "Storage", 3000, 0, "") }); mDatabase.getMapper().stopAddingDocuments("1"); mDatabase.getMapper().stopAddingDocuments("2"); @@ -482,18 +482,18 @@ public class MtpDatabaseTest extends AndroidTestCase { final Cursor cursor = mDatabase.queryRootDocuments(columns); assertEquals(2, cursor.getCount()); cursor.moveToNext(); - assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID)); + assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.moveToNext(); - assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID)); + assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.close(); } { - final Cursor cursor = mDatabase.queryRoots(rootColumns); + final Cursor cursor = mDatabase.queryRoots(resources, rootColumns); assertEquals(2, cursor.getCount()); cursor.moveToNext(); assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID)); @@ -562,24 +562,24 @@ public class MtpDatabaseTest extends AndroidTestCase { mDatabase.getMapper().startAddingDocuments(null); mDatabase.getMapper().putDeviceDocument( - new MtpDeviceRecord(0, "Device", false, new MtpRoot[0], null, null)); + new MtpDeviceRecord(0, "Device", false, new MtpRoot[0], null, null)); mDatabase.getMapper().stopAddingDocuments(null); mDatabase.getMapper().startAddingDocuments("1"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage", 0, 0, ""), + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 100, "Storage", 0, 0, ""), }); mDatabase.getMapper().clearMapping(); mDatabase.getMapper().startAddingDocuments("1"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 200, "Device", "Storage", 2000, 0, ""), + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 200, "Storage", 2000, 0, ""), }); mDatabase.getMapper().clearMapping(); mDatabase.getMapper().startAddingDocuments("1"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 300, "Device", "Storage", 3000, 0, ""), + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 300, "Storage", 3000, 0, ""), }); mDatabase.getMapper().stopAddingDocuments("1"); @@ -589,11 +589,11 @@ public class MtpDatabaseTest extends AndroidTestCase { cursor.moveToNext(); assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.close(); } { - final Cursor cursor = mDatabase.queryRoots(rootColumns); + final Cursor cursor = mDatabase.queryRoots(resources, rootColumns); assertEquals(1, cursor.getCount()); cursor.moveToNext(); assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID)); @@ -610,15 +610,15 @@ public class MtpDatabaseTest extends AndroidTestCase { }; mDatabase.getMapper().startAddingDocuments("deviceDocId"); - mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage", 0, 0, ""), + mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] { + new MtpRoot(0, 100, "Storage", 0, 0, ""), }); mDatabase.getMapper().clearMapping(); mDatabase.getMapper().startAddingDocuments("deviceDocId"); - mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] { - new MtpRoot(0, 200, "Device", "Storage", 2000, 0, ""), - new MtpRoot(0, 201, "Device", "Storage", 2001, 0, ""), + mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] { + new MtpRoot(0, 200, "Storage", 2000, 0, ""), + new MtpRoot(0, 201, "Storage", 2001, 0, ""), }); mDatabase.getMapper().stopAddingDocuments("deviceDocId"); @@ -628,11 +628,11 @@ public class MtpDatabaseTest extends AndroidTestCase { cursor.moveToNext(); assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.moveToNext(); assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(201, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.close(); } } @@ -646,14 +646,14 @@ public class MtpDatabaseTest extends AndroidTestCase { // The client code should be able to replace existing rows with new information. // Add one. mDatabase.getMapper().startAddingDocuments("1"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""), + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 100, "Storage A", 0, 0, ""), }); mDatabase.getMapper().stopAddingDocuments("1"); // Replace it. mDatabase.getMapper().startAddingDocuments("1"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage B", 1000, 1000, ""), + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 100, "Storage B", 1000, 1000, ""), }); mDatabase.getMapper().stopAddingDocuments("1"); { @@ -667,7 +667,7 @@ public class MtpDatabaseTest extends AndroidTestCase { cursor.moveToNext(); assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID)); - assertEquals("Device Storage B", getString(cursor, COLUMN_DISPLAY_NAME)); + assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME)); cursor.close(); } { @@ -676,7 +676,7 @@ public class MtpDatabaseTest extends AndroidTestCase { Root.COLUMN_TITLE, Root.COLUMN_AVAILABLE_BYTES }; - final Cursor cursor = mDatabase.queryRoots(columns); + final Cursor cursor = mDatabase.queryRoots(resources, columns); assertEquals(1, cursor.getCount()); cursor.moveToNext(); assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID)); @@ -695,21 +695,21 @@ public class MtpDatabaseTest extends AndroidTestCase { mDatabase.getMapper().stopAddingDocuments(null); mDatabase.getMapper().startAddingDocuments("1"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""), + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 100, "Storage A", 0, 0, ""), }); mDatabase.getMapper().clearMapping(); - final Cursor oldCursor = mDatabase.queryRoots(strings(Root.COLUMN_ROOT_ID)); + final Cursor oldCursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_ROOT_ID)); assertEquals(1, oldCursor.getCount()); // Add one. mDatabase.getMapper().startAddingDocuments("1"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 101, "Device", "Storage B", 1000, 1000, ""), + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 101, "Storage B", 1000, 1000, ""), }); // Add one more before resolving unmapped documents. - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 102, "Device", "Storage B", 1000, 1000, ""), + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 102, "Storage B", 1000, 1000, ""), }); mDatabase.getMapper().stopAddingDocuments("1"); @@ -729,15 +729,15 @@ public class MtpDatabaseTest extends AndroidTestCase { public void testQueryDocuments() { mDatabase.getMapper().startAddingDocuments("deviceDocId"); - mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""), + mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] { + new MtpRoot(0, 100, "Storage A", 0, 0, ""), }); mDatabase.getMapper().stopAddingDocuments("deviceDocId"); final Cursor cursor = mDatabase.queryDocument("1", strings(Document.COLUMN_DISPLAY_NAME)); assertEquals(1, cursor.getCount()); cursor.moveToNext(); - assertEquals("Device Storage A", getString(cursor, Document.COLUMN_DISPLAY_NAME)); + assertEquals("Storage A", getString(cursor, Document.COLUMN_DISPLAY_NAME)); cursor.close(); } @@ -750,7 +750,7 @@ public class MtpDatabaseTest extends AndroidTestCase { // It the device does not have storages, it shows a device root. { - final Cursor cursor = mDatabase.queryRoots(strings(Root.COLUMN_TITLE)); + final Cursor cursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_TITLE)); assertEquals(1, cursor.getCount()); cursor.moveToNext(); assertEquals("Device", cursor.getString(0)); @@ -758,14 +758,14 @@ public class MtpDatabaseTest extends AndroidTestCase { } mDatabase.getMapper().startAddingDocuments("1"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage A", 0, 0, "") + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 100, "Storage A", 0, 0, "") }); mDatabase.getMapper().stopAddingDocuments("1"); // It the device has single storage, it shows a storage root. { - final Cursor cursor = mDatabase.queryRoots(strings(Root.COLUMN_TITLE)); + final Cursor cursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_TITLE)); assertEquals(1, cursor.getCount()); cursor.moveToNext(); assertEquals("Device Storage A", cursor.getString(0)); @@ -773,15 +773,15 @@ public class MtpDatabaseTest extends AndroidTestCase { } mDatabase.getMapper().startAddingDocuments("1"); - mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""), - new MtpRoot(0, 101, "Device", "Storage B", 0, 0, "") + mDatabase.getMapper().putStorageDocuments("1", new MtpRoot[] { + new MtpRoot(0, 100, "Storage A", 0, 0, ""), + new MtpRoot(0, 101, "Storage B", 0, 0, "") }); mDatabase.getMapper().stopAddingDocuments("1"); // It the device has multiple storages, it shows a device root. { - final Cursor cursor = mDatabase.queryRoots(strings(Root.COLUMN_TITLE)); + final Cursor cursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_TITLE)); assertEquals(1, cursor.getCount()); cursor.moveToNext(); assertEquals("Device", cursor.getString(0)); @@ -791,8 +791,8 @@ public class MtpDatabaseTest extends AndroidTestCase { public void testGetParentId() throws FileNotFoundException { mDatabase.getMapper().startAddingDocuments("deviceDocId"); - mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""), + mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] { + new MtpRoot(0, 100, "Storage A", 0, 0, ""), }); mDatabase.getMapper().stopAddingDocuments("deviceDocId"); @@ -810,8 +810,8 @@ public class MtpDatabaseTest extends AndroidTestCase { public void testDeleteDocument() { mDatabase.getMapper().startAddingDocuments("deviceDocId"); - mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""), + mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] { + new MtpRoot(0, 100, "Storage A", 0, 0, ""), }); mDatabase.getMapper().stopAddingDocuments("deviceDocId"); @@ -854,8 +854,8 @@ public class MtpDatabaseTest extends AndroidTestCase { public void testPutNewDocument() { mDatabase.getMapper().startAddingDocuments("deviceDocId"); - mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] { - new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""), + mDatabase.getMapper().putStorageDocuments("deviceDocId", new MtpRoot[] { + new MtpRoot(0, 100, "Storage A", 0, 0, ""), }); mDatabase.getMapper().stopAddingDocuments("deviceDocId"); @@ -911,7 +911,7 @@ public class MtpDatabaseTest extends AndroidTestCase { DocumentsContract.Root.COLUMN_TITLE, DocumentsContract.Root.COLUMN_AVAILABLE_BYTES }; - try (final Cursor cursor = mDatabase.queryRoots(columns)) { + try (final Cursor cursor = mDatabase.queryRoots(resources, columns)) { assertEquals(1, cursor.getCount()); assertTrue(cursor.moveToNext()); assertEquals(1, cursor.getLong(0)); diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java index 360661270240..5b0f55703a2b 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java @@ -23,13 +23,11 @@ import android.net.Uri; import android.os.ParcelFileDescriptor; import android.os.storage.StorageManager; import android.provider.DocumentsContract.Root; -import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.provider.DocumentsContract; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.MediumTest; -import android.util.Log; import java.io.FileNotFoundException; import java.io.IOException; @@ -64,13 +62,12 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); mMtpManager.addValidDevice(new MtpDeviceRecord( 0, - "Device", + "Device A", false /* unopened */, new MtpRoot[] { new MtpRoot( 0 /* deviceId */, 1 /* storageId */, - "Device A" /* device model name */, "Storage A" /* volume description */, 1024 /* free space */, 2048 /* total space */, @@ -79,11 +76,14 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { null, null)); - mProvider.openDevice(0); + mProvider.resumeRootScanner(); mResolver.waitForNotification(ROOTS_URI, 1); - mProvider.closeDevice(0); + mProvider.openDevice(0); mResolver.waitForNotification(ROOTS_URI, 2); + + mProvider.closeDevice(0); + mResolver.waitForNotification(ROOTS_URI, 3); } public void testOpenAndCloseErrorDevice() throws Exception { @@ -94,24 +94,17 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { } catch (Throwable error) { assertTrue(error instanceof IOException); } - - try { - mProvider.closeDevice(1); - fail(); - } catch (Throwable error) { - assertTrue(error instanceof IOException); - } + assertEquals(0, mProvider.getOpenedDeviceIds().length); // Check if the following notification is the first one or not. mMtpManager.addValidDevice(new MtpDeviceRecord( 0, - "Device", + "Device A", false /* unopened */, new MtpRoot[] { new MtpRoot( 0 /* deviceId */, 1 /* storageId */, - "Device A" /* device model name */, "Storage A" /* volume description */, 1024 /* free space */, 2048 /* total space */, @@ -119,21 +112,66 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { }, null, null)); + mProvider.resumeRootScanner(); + mResolver.waitForNotification(ROOTS_URI, 1); mProvider.openDevice(0); + mResolver.waitForNotification(ROOTS_URI, 2); + } + + public void testOpenDeviceOnDemand() throws Exception { + setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); + mMtpManager.addValidDevice(new MtpDeviceRecord( + 0, + "Device A", + false /* unopened */, + new MtpRoot[] { + new MtpRoot( + 0 /* deviceId */, + 1 /* storageId */, + "Storage A" /* volume description */, + 1024 /* free space */, + 2048 /* total space */, + "" /* no volume identifier */) + }, + null, + null)); + mMtpManager.setObjectHandles(0, 1, -1, new int[0]); + mProvider.resumeRootScanner(); mResolver.waitForNotification(ROOTS_URI, 1); + final String[] columns = new String[] { + DocumentsContract.Root.COLUMN_TITLE, + DocumentsContract.Root.COLUMN_DOCUMENT_ID + }; + try (final Cursor cursor = mProvider.queryRoots(columns)) { + assertEquals(1, cursor.getCount()); + assertTrue(cursor.moveToNext()); + assertEquals("Device A", cursor.getString(0)); + assertEquals(1, cursor.getLong(1)); + } + { + final int [] openedDevice = mProvider.getOpenedDeviceIds(); + assertEquals(0, openedDevice.length); + } + // Device is opened automatically when querying its children. + try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) {} + + { + final int [] openedDevice = mProvider.getOpenedDeviceIds(); + assertEquals(1, openedDevice.length); + assertEquals(0, openedDevice[0]); + } } public void testQueryRoots() throws Exception { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); mMtpManager.addValidDevice(new MtpDeviceRecord( 0, - "Device", + "Device A", false /* unopened */, new MtpRoot[] { new MtpRoot( 0 /* deviceId */, 1 /* storageId */, - "Device A" /* device model name */, "Storage A" /* volume description */, 1024 /* free space */, 2048 /* total space */, @@ -143,13 +181,12 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { null)); mMtpManager.addValidDevice(new MtpDeviceRecord( 1, - "Device", + "Device B", false /* unopened */, new MtpRoot[] { new MtpRoot( 1 /* deviceId */, 1 /* storageId */, - "Device B" /* device model name */, "Storage B" /* volume description */, 2048 /* free space */, 4096 /* total space */, @@ -194,13 +231,12 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { 0, "Device A", false /* unopened */, new MtpRoot[0], null, null)); mMtpManager.addValidDevice(new MtpDeviceRecord( 1, - "Device", + "Device B", false /* unopened */, new MtpRoot[] { new MtpRoot( 1 /* deviceId */, 1 /* storageId */, - "Device B" /* device model name */, "Storage B" /* volume description */, 2048 /* free space */, 4096 /* total space */, @@ -210,9 +246,13 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { null)); { mProvider.openDevice(0); - mProvider.openDevice(1); + mProvider.resumeRootScanner(); mResolver.waitForNotification(ROOTS_URI, 1); + mProvider.openDevice(1); + mProvider.resumeRootScanner(); + mResolver.waitForNotification(ROOTS_URI, 2); + final Cursor cursor = mProvider.queryRoots(null); assertEquals(2, cursor.getCount()); @@ -236,7 +276,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { public void testQueryDocument() throws IOException, InterruptedException, TimeoutException { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); - setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") }); + setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") }); setupDocuments( 0, 0, @@ -273,7 +313,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { public void testQueryDocument_directory() throws IOException, InterruptedException, TimeoutException { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); - setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") }); + setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") }); setupDocuments( 0, 0, @@ -312,7 +352,6 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { new MtpRoot( 0 /* deviceId */, 1 /* storageId */, - "Device A" /* device model name */, "Storage A" /* volume description */, 1024 /* free space */, 4096 /* total space */, @@ -324,7 +363,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { cursor.moveToNext(); assertEquals("2", cursor.getString(0)); assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1)); - assertEquals("Device A Storage A", cursor.getString(2)); + assertEquals("Storage A", cursor.getString(2)); assertTrue(cursor.isNull(3)); assertEquals(0, cursor.getInt(4)); assertEquals(3072, cursor.getInt(5)); @@ -332,7 +371,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { public void testQueryChildDocuments() throws Exception { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); - setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") }); + setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") }); setupDocuments( 0, 0, @@ -375,7 +414,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { public void testQueryChildDocuments_documentError() throws Exception { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); - setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") }); + setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") }); mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 }); try { mProvider.queryChildDocuments("1", null, null); @@ -388,7 +427,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { public void testDeleteDocument() throws IOException, InterruptedException, TimeoutException { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); setupRoots(0, new MtpRoot[] { - new MtpRoot(0, 0, "Device", "Storage", 0, 0, "") + new MtpRoot(0, 0, "Storage", 0, 0, "") }); setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] { new MtpObjectInfo.Builder() @@ -408,7 +447,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { throws IOException, InterruptedException, TimeoutException { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); setupRoots(0, new MtpRoot[] { - new MtpRoot(0, 0, "Device", "Storage", 0, 0, "") + new MtpRoot(0, 0, "Storage", 0, 0, "") }); setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] { new MtpObjectInfo.Builder() @@ -431,7 +470,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { public void testOpenDocument() throws Exception { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); setupRoots(0, new MtpRoot[] { - new MtpRoot(0, 0, "Device", "Storage", 0, 0, "") + new MtpRoot(0, 0, "Storage", 0, 0, "") }); final byte[] bytes = "Hello world".getBytes(); setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] { @@ -469,7 +508,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { }; setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); setupRoots(0, new MtpRoot[] { - new MtpRoot(0, 0, "Device", "Storage", 0, 0, "") + new MtpRoot(0, 0, "Storage", 0, 0, "") }); final byte[] bytes = "Hello world".getBytes(); setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] { @@ -492,7 +531,12 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { mProvider = new MtpDocumentsProvider(); final StorageManager storageManager = getContext().getSystemService(StorageManager.class); assertTrue(mProvider.onCreateForTesting( - mResources, mMtpManager, mResolver, mDatabase, storageManager)); + mResources, + mMtpManager, + mResolver, + mDatabase, + storageManager, + new TestServiceIntentSender())); } private String[] getStrings(Cursor cursor) { diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java index eb80e3b60e6a..b23038b6c3f6 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java @@ -27,4 +27,9 @@ class TestResources extends MockResources { } throw new NotFoundException(); } + + @Override + public String getString(int id, Object... formatArgs) throws NotFoundException { + return String.format(getString(id), formatArgs); + } } diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java new file mode 100644 index 000000000000..d4a4a487d8ee --- /dev/null +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java @@ -0,0 +1,26 @@ +/* + * 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.mtp; + +class TestServiceIntentSender extends ServiceIntentSender { + TestServiceIntentSender() { + super(null); + } + + @Override + void sendUpdateNotificationIntent() {} +} diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java index a1ea658e5aff..d0cf6351d018 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java @@ -265,7 +265,14 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat new Runnable() { @Override public void run() { - onConnectedToPrintSpooler(adapter); + if (isFinishing()) { + // onPause might have not been able to cancel the job, see PrintActivity#onPause + // To be sure, cancel the job again. Double canceling does no harm. + mSpoolerProvider.getSpooler().setPrintJobState(mPrintJob.getId(), + PrintJobInfo.STATE_CANCELED, null); + } else { + onConnectedToPrintSpooler(adapter); + } } }); } @@ -353,7 +360,9 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat if (mState == STATE_INITIALIZING) { if (isFinishing()) { - spooler.setPrintJobState(mPrintJob.getId(), PrintJobInfo.STATE_CANCELED, null); + if (spooler != null) { + spooler.setPrintJobState(mPrintJob.getId(), PrintJobInfo.STATE_CANCELED, null); + } } super.onPause(); return; diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index d3c8416a4abb..38d890777994 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -515,9 +515,9 @@ <string name="pointer_location_summary">Screen overlay showing current touch data</string> <!-- UI debug setting: show touches? [CHAR LIMIT=25] --> - <string name="show_touches">Show touches</string> + <string name="show_touches">Show taps</string> <!-- UI debug setting: show touches location summary [CHAR LIMIT=50] --> - <string name="show_touches_summary">Show visual feedback for touches</string> + <string name="show_touches_summary">Show visual feedback for taps</string> <!-- UI debug setting: show where surface updates happen? [CHAR LIMIT=25] --> <string name="show_screen_updates">Show surface updates</string> @@ -634,7 +634,7 @@ <!-- Summary text of the "local backup password" setting when the user has not supplied a password --> <string name="local_backup_password_summary_none">Desktop full backups aren\u2019t currently protected</string> <!-- Summary text of the "local backup password" setting when the user has already supplied a password --> - <string name="local_backup_password_summary_change">Touch to change or remove the password for desktop full backups</string> + <string name="local_backup_password_summary_change">Tap to change or remove the password for desktop full backups</string> <!-- Toast message shown when the user successfully sets a new local backup password [CHAR LIMIT=80] --> <string name="local_backup_password_toast_success">New backup password set</string> @@ -660,9 +660,9 @@ <!-- Settings item title for inactive apps [CHAR LIMIT=35] --> <string name="inactive_apps_title">Inactive apps</string> <!-- Settings item summary for inactive app [CHAR LIMIT=100] --> - <string name="inactive_app_inactive_summary">Inactive. Touch to toggle.</string> + <string name="inactive_app_inactive_summary">Inactive. Tap to toggle.</string> <!-- Settings item summary for active app [CHAR LIMIT=100] --> - <string name="inactive_app_active_summary">Active. Touch to toggle.</string> + <string name="inactive_app_active_summary">Active. Tap to toggle.</string> <!-- Services settings screen, setting option name for the user to go to the screen to view running services --> <string name="runningservices_settings_title">Running services</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java index 85cc3e44bba8..f8851101abc2 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java @@ -155,7 +155,7 @@ public class RestrictedLockUtils { for (UserInfo userInfo : um.getProfiles(userId)) { final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id); if (admins == null) { - return null; + continue; } final boolean isSeparateProfileChallengeEnabled = lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id); @@ -209,16 +209,7 @@ public class RestrictedLockUtils { IPackageManager ipm = AppGlobals.getPackageManager(); try { if (ipm.getBlockUninstallForUser(packageName, userId)) { - DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( - Context.DEVICE_POLICY_SERVICE); - if (dpm == null) { - return null; - } - ComponentName admin = dpm.getProfileOwner(); - if (admin == null) { - admin = dpm.getDeviceOwnerComponentOnCallingUser(); - } - return new EnforcedAdmin(admin, UserHandle.myUserId()); + return getProfileOrDeviceOwner(context, userId); } } catch (RemoteException e) { // Nothing to do @@ -238,7 +229,7 @@ public class RestrictedLockUtils { try { ApplicationInfo ai = ipm.getApplicationInfo(packageName, 0, userId); if (ai != null && ((ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0)) { - return getProfileOrDeviceOwnerOnCallingUser(context); + return getProfileOrDeviceOwner(context, userId); } } catch (RemoteException e) { // Nothing to do @@ -246,6 +237,80 @@ public class RestrictedLockUtils { return null; } + public static EnforcedAdmin checkIfInputMethodDisallowed(Context context, + String packageName, int userId) { + DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( + Context.DEVICE_POLICY_SERVICE); + if (dpm == null) { + return null; + } + EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId); + boolean permitted = true; + if (admin != null) { + permitted = dpm.isInputMethodPermittedByAdmin(admin.component, + packageName, userId); + } + int managedProfileId = getManagedProfileId(context, userId); + EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId); + boolean permittedByProfileAdmin = true; + if (profileAdmin != null) { + permittedByProfileAdmin = dpm.isInputMethodPermittedByAdmin(profileAdmin.component, + packageName, managedProfileId); + } + if (!permitted && !permittedByProfileAdmin) { + return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; + } else if (!permitted) { + return admin; + } else if (!permittedByProfileAdmin) { + return profileAdmin; + } + return null; + } + + public static EnforcedAdmin checkIfAccessibilityServiceDisallowed(Context context, + String packageName, int userId) { + DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( + Context.DEVICE_POLICY_SERVICE); + if (dpm == null) { + return null; + } + EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId); + boolean permitted = true; + if (admin != null) { + permitted = dpm.isAccessibilityServicePermittedByAdmin(admin.component, + packageName, userId); + } + int managedProfileId = getManagedProfileId(context, userId); + EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId); + boolean permittedByProfileAdmin = true; + if (profileAdmin != null) { + permittedByProfileAdmin = dpm.isAccessibilityServicePermittedByAdmin( + profileAdmin.component, packageName, managedProfileId); + } + if (!permitted && !permittedByProfileAdmin) { + return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; + } else if (!permitted) { + return admin; + } else if (!permittedByProfileAdmin) { + return profileAdmin; + } + return null; + } + + private static int getManagedProfileId(Context context, int userId) { + UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); + List<UserInfo> userProfiles = um.getProfiles(userId); + for (UserInfo uInfo : userProfiles) { + if (uInfo.id == userId) { + continue; + } + if (uInfo.isManagedProfile()) { + return uInfo.id; + } + } + return UserHandle.USER_NULL; + } + /** * Check if account management for a specific type of account is disabled by admin. * Only a profile or device owner can disable account management. So, we check if account @@ -255,7 +320,7 @@ public class RestrictedLockUtils { * or {@code null} if the account management is not disabled. */ public static EnforcedAdmin checkIfAccountManagementDisabled(Context context, - String accountType) { + String accountType, int userId) { if (accountType == null) { return null; } @@ -265,7 +330,7 @@ public class RestrictedLockUtils { return null; } boolean isAccountTypeDisabled = false; - String[] disabledTypes = dpm.getAccountTypesWithManagementDisabled(); + String[] disabledTypes = dpm.getAccountTypesWithManagementDisabledAsUser(userId); for (String type : disabledTypes) { if (accountType.equals(type)) { isAccountTypeDisabled = true; @@ -275,7 +340,7 @@ public class RestrictedLockUtils { if (!isAccountTypeDisabled) { return null; } - return getProfileOrDeviceOwnerOnCallingUser(context); + return getProfileOrDeviceOwner(context, userId); } /** @@ -296,7 +361,7 @@ public class RestrictedLockUtils { } /** - * Checks if an admin has enforced minimum password quality requirements on the device. + * Checks if an admin has enforced minimum password quality requirements on the given user. * * @return EnforcedAdmin Object containing the enforced admin component and admin user details, * or {@code null} if no quality requirements are set. If the requirements are set by @@ -304,35 +369,73 @@ public class RestrictedLockUtils { * {@link UserHandle#USER_NULL}. * */ - public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context) { + public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context, int userId) { final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( Context.DEVICE_POLICY_SERVICE); if (dpm == null) { return null; } - boolean isDisabledByMultipleAdmins = false; - ComponentName adminComponent = null; - List<ComponentName> admins = dpm.getActiveAdmins(); - int quality; - if (admins != null) { + + LockPatternUtils lockPatternUtils = new LockPatternUtils(context); + EnforcedAdmin enforcedAdmin = null; + if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) { + // userId is managed profile and has a separate challenge, only consider + // the admins in that user. + final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId); + if (admins == null) { + return null; + } for (ComponentName admin : admins) { - quality = dpm.getPasswordQuality(admin); - if (quality >= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { - if (adminComponent == null) { - adminComponent = admin; + if (dpm.getPasswordQuality(admin, userId) + > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { + if (enforcedAdmin == null) { + enforcedAdmin = new EnforcedAdmin(admin, userId); } else { - isDisabledByMultipleAdmins = true; - break; + return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; } } } - } - EnforcedAdmin enforcedAdmin = null; - if (adminComponent != null) { - if (!isDisabledByMultipleAdmins) { - enforcedAdmin = new EnforcedAdmin(adminComponent, UserHandle.myUserId()); - } else { - enforcedAdmin = new EnforcedAdmin(); + } else { + // Return all admins for this user and the profiles that are visible from this + // user that do not use a separate work challenge. + final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); + for (UserInfo userInfo : um.getProfiles(userId)) { + final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id); + if (admins == null) { + continue; + } + final boolean isSeparateProfileChallengeEnabled = + lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id); + for (ComponentName admin : admins) { + if (!isSeparateProfileChallengeEnabled) { + if (dpm.getPasswordQuality(admin, userInfo.id) + > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { + if (enforcedAdmin == null) { + enforcedAdmin = new EnforcedAdmin(admin, userInfo.id); + } else { + return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; + } + // This same admins could have set policies both on the managed profile + // and on the parent. So, if the admin has set the policy on the + // managed profile here, we don't need to further check if that admin + // has set policy on the parent admin. + continue; + } + } + if (userInfo.isManagedProfile()) { + // If userInfo.id is a managed profile, we also need to look at + // the policies set on the parent. + DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo); + if (parentDpm.getPasswordQuality(admin, userInfo.id) + > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { + if (enforcedAdmin == null) { + enforcedAdmin = new EnforcedAdmin(admin, userInfo.id); + } else { + return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; + } + } + } + } } } return enforcedAdmin; @@ -352,7 +455,8 @@ public class RestrictedLockUtils { EnforcedAdmin enforcedAdmin = null; final int userId = UserHandle.myUserId(); if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) { - // If the user has a separate challenge, only consider the admins in that user. + // userId is managed profile and has a separate challenge, only consider + // the admins in that user. final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId); if (admins == null) { return null; @@ -373,7 +477,7 @@ public class RestrictedLockUtils { for (UserInfo userInfo : um.getProfiles(userId)) { final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id); if (admins == null) { - return null; + continue; } final boolean isSeparateProfileChallengeEnabled = lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id); @@ -410,19 +514,37 @@ public class RestrictedLockUtils { return enforcedAdmin; } - public static EnforcedAdmin getProfileOrDeviceOwnerOnCallingUser(Context context) { + public static EnforcedAdmin getProfileOrDeviceOwner(Context context, int userId) { + if (userId == UserHandle.USER_NULL) { + return null; + } final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( Context.DEVICE_POLICY_SERVICE); if (dpm == null) { return null; } - ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser(); + ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId); if (adminComponent != null) { - return new EnforcedAdmin(adminComponent, UserHandle.myUserId()); + return new EnforcedAdmin(adminComponent, userId); + } + if (dpm.getDeviceOwnerUserId() == userId) { + adminComponent = dpm.getDeviceOwnerComponentOnAnyUser(); + if (adminComponent != null) { + return new EnforcedAdmin(adminComponent, userId); + } + } + return null; + } + + public static EnforcedAdmin getDeviceOwner(Context context) { + final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( + Context.DEVICE_POLICY_SERVICE); + if (dpm == null) { + return null; } - adminComponent = dpm.getProfileOwner(); + ComponentName adminComponent = dpm.getDeviceOwnerComponentOnAnyUser(); if (adminComponent != null) { - return new EnforcedAdmin(adminComponent, UserHandle.myUserId()); + return new EnforcedAdmin(adminComponent, dpm.getDeviceOwnerUserId()); } return null; } diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java index f5a2aaec97d7..d368de93e263 100644 --- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java +++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java @@ -15,40 +15,19 @@ */ package com.android.settingslib; -import android.app.ActivityManager; -import android.content.ComponentName; -import android.content.ContentResolver; import android.content.Context; -import android.content.res.Resources; -import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.SystemProperties; -import android.os.UserManager; -import android.provider.Settings; import android.telephony.CarrierConfigManager; public class TetherUtil { - // Extras used for communicating with the TetherService. - public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType"; - public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType"; - public static final String EXTRA_SET_ALARM = "extraSetAlarm"; - /** - * Tells the service to run a provision check now. - */ - public static final String EXTRA_RUN_PROVISION = "extraRunProvision"; - public static boolean setWifiTethering(boolean enable, Context context) { final WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); return wifiManager.setWifiApEnabled(null, enable); } - public static boolean isWifiTetherEnabled(Context context) { - WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - return wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED; - } - private static boolean isEntitlementCheckRequired(Context context) { final CarrierConfigManager configManager = (CarrierConfigManager) context .getSystemService(Context.CARRIER_CONFIG_SERVICE); @@ -71,13 +50,4 @@ public class TetherUtil { } return (provisionApp.length == 2); } - - public static boolean isTetheringSupported(Context context) { - final ConnectivityManager cm = - (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - final boolean isAdminUser = - UserManager.get(context).isUserAdmin(ActivityManager.getCurrentUser()); - return isAdminUser && cm.isTetheringSupported(); - } - } diff --git a/packages/SystemUI/res/anim/recents_from_app_enter.xml b/packages/SystemUI/res/anim/recents_from_app_enter.xml deleted file mode 100644 index 10ddce68dcaf..000000000000 --- a/packages/SystemUI/res/anim/recents_from_app_enter.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** Copyright 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. -*/ ---> -<!-- Recents Activity --> -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" - android:zAdjustment="top"> - <alpha android:fromAlpha="1.0" android:toAlpha="1.0" - android:fillEnabled="true" - android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/fast_out_slow_in" - android:duration="0"/> -</set> diff --git a/packages/SystemUI/res/anim/recents_from_app_exit.xml b/packages/SystemUI/res/anim/recents_from_app_exit.xml deleted file mode 100644 index c98ecf43eb65..000000000000 --- a/packages/SystemUI/res/anim/recents_from_app_exit.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** Copyright 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. -*/ ---> -<!-- Incoming Activity --> -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" - android:zAdjustment="normal"> - - <!-- Animate the view out only after recents is visible --> - <alpha android:fromAlpha="1.0" android:toAlpha="0.0" - android:fillEnabled="true" - android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/fast_out_slow_in" - android:duration="1"/> -</set> diff --git a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml b/packages/SystemUI/res/anim/recents_from_launcher_enter.xml index b191e625177b..00b3dfda135e 100644 --- a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml +++ b/packages/SystemUI/res/anim/recents_from_launcher_enter.xml @@ -23,6 +23,6 @@ <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/linear" + android:interpolator="@android:interpolator/linear_out_slow_in" android:duration="150"/> </set> diff --git a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml b/packages/SystemUI/res/anim/recents_from_launcher_exit.xml index fa6caf295cce..33831b8c0a32 100644 --- a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml +++ b/packages/SystemUI/res/anim/recents_from_launcher_exit.xml @@ -23,6 +23,6 @@ <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/linear_out_slow_in" - android:duration="150"/> + android:interpolator="@interpolator/recents_from_launcher_exit_interpolator" + android:duration="133"/> </set> diff --git a/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml b/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml index e0e2fc83a816..23cedf85adf6 100644 --- a/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml +++ b/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml @@ -23,6 +23,6 @@ <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/linear_out_slow_in" - android:duration="@integer/recents_enter_from_home_transition_duration"/> + android:interpolator="@interpolator/recents_from_launcher_exit_interpolator" + android:duration="133"/> </set> diff --git a/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml b/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml deleted file mode 100644 index 1135bc097fcf..000000000000 --- a/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** Copyright 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. -*/ ---> - -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" - android:zAdjustment="normal"> - <!--scale android:fromXScale="2.0" android:toXScale="1.0" - android:fromYScale="2.0" android:toYScale="1.0" - android:interpolator="@android:interpolator/decelerate_cubic" - android:fillEnabled="true" - android:fillBefore="true" android:fillAfter="true" - android:pivotX="50%p" android:pivotY="50%p" - android:duration="250" /--> -</set> diff --git a/packages/SystemUI/res/anim/recents_return_to_launcher_exit.xml b/packages/SystemUI/res/anim/recents_return_to_launcher_exit.xml deleted file mode 100644 index e95e667507f3..000000000000 --- a/packages/SystemUI/res/anim/recents_return_to_launcher_exit.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** Copyright 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. -*/ ---> - -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" - android:zAdjustment="normal"> - <!--scale android:fromXScale="1.0" android:toXScale="2.0" - android:fromYScale="1.0" android:toYScale="2.0" - android:interpolator="@android:interpolator/decelerate_cubic" - android:pivotX="50%p" android:pivotY="50%p" - android:duration="250" /--> - <alpha android:fromAlpha="1.0" android:toAlpha="0.0" - android:interpolator="@android:interpolator/decelerate_cubic" - android:duration="250"/> -</set> diff --git a/packages/SystemUI/res/anim/recents_to_launcher_enter.xml b/packages/SystemUI/res/anim/recents_to_launcher_enter.xml index b191e625177b..544ec88d2bfa 100644 --- a/packages/SystemUI/res/anim/recents_to_launcher_enter.xml +++ b/packages/SystemUI/res/anim/recents_to_launcher_enter.xml @@ -23,6 +23,6 @@ <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/linear" - android:duration="150"/> + android:interpolator="@interpolator/recents_to_launcher_enter_interpolator" + android:duration="133"/> </set> diff --git a/packages/SystemUI/res/anim/recents_to_launcher_exit.xml b/packages/SystemUI/res/anim/recents_to_launcher_exit.xml index fa6caf295cce..226edb85d049 100644 --- a/packages/SystemUI/res/anim/recents_to_launcher_exit.xml +++ b/packages/SystemUI/res/anim/recents_to_launcher_exit.xml @@ -24,5 +24,5 @@ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" android:interpolator="@android:interpolator/linear_out_slow_in" - android:duration="150"/> + android:duration="1"/> </set> diff --git a/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml b/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml index ea8283511b96..657b2164d6f2 100644 --- a/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml +++ b/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml @@ -23,6 +23,6 @@ <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/linear" - android:duration="100"/> + android:interpolator="@interpolator/recents_to_launcher_enter_interpolator" + android:duration="133"/> </set> diff --git a/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml b/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml index a8bdc8e45f59..5182cab29ee4 100644 --- a/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml +++ b/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml @@ -24,5 +24,5 @@ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" android:interpolator="@android:interpolator/linear" - android:duration="100"/> + android:duration="1"/> </set> diff --git a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml deleted file mode 100644 index 73ae9f2a25ee..000000000000 --- a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** Copyright 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. -*/ ---> - -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:detachWallpaper="true" - android:shareInterpolator="false" - android:zAdjustment="normal"> - <!--scale android:fromXScale="2.0" android:toXScale="1.0" - android:fromYScale="2.0" android:toYScale="1.0" - android:interpolator="@android:interpolator/decelerate_cubic" - android:fillEnabled="true" - android:fillBefore="true" android:fillAfter="true" - android:pivotX="50%p" android:pivotY="50%p" - android:duration="250" /--> - <alpha android:fromAlpha="0.0" android:toAlpha="1.0" - android:fillEnabled="true" - android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/decelerate_cubic" - android:duration="250"/> -</set> diff --git a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml deleted file mode 100644 index 7e257d938e71..000000000000 --- a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** Copyright 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. -*/ ---> - -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:detachWallpaper="true" - android:shareInterpolator="false" - android:zAdjustment="top"> - <alpha android:fromAlpha="1.0" android:toAlpha="0.0" - android:fillEnabled="true" - android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/decelerate_cubic" - android:duration="250"/> -</set> diff --git a/packages/SystemUI/res/anim/recents_return_to_launcher_enter.xml b/packages/SystemUI/res/interpolator/recents_from_launcher_exit_interpolator.xml index efa901915886..4a7fff67eac5 100644 --- a/packages/SystemUI/res/anim/recents_return_to_launcher_enter.xml +++ b/packages/SystemUI/res/interpolator/recents_from_launcher_exit_interpolator.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <!-- /* -** Copyright 2012, The Android Open Source Project +** Copyright 2014, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -16,11 +16,8 @@ ** limitations under the License. */ --> - -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" - android:zAdjustment="normal"> - <alpha android:fromAlpha="0.0" android:toAlpha="1.0" - android:interpolator="@android:interpolator/decelerate_cubic" - android:duration="250"/> -</set> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:controlX1="0" + android:controlY1="0" + android:controlX2="0.8" + android:controlY2="1" /> diff --git a/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml b/packages/SystemUI/res/interpolator/recents_to_launcher_enter_interpolator.xml index fa28cf42eee9..c61dfd87d842 100644 --- a/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml +++ b/packages/SystemUI/res/interpolator/recents_to_launcher_enter_interpolator.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <!-- /* -** Copyright 2012, The Android Open Source Project +** Copyright 2014, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -16,13 +16,8 @@ ** limitations under the License. */ --> - -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:shareInterpolator="false" - android:zAdjustment="top"> - <alpha android:fromAlpha="1.0" android:toAlpha="0.0" - android:fillEnabled="true" - android:fillBefore="true" android:fillAfter="true" - android:interpolator="@android:interpolator/decelerate_cubic" - android:duration="250"/> -</set> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:controlX1="0.4" + android:controlY1="0" + android:controlX2="1" + android:controlY2="1" /> diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_separator.xml index 802acfed73e8..778ef8ffd3dd 100644 --- a/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_separator.xml @@ -15,8 +15,11 @@ ~ limitations under the License --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="wrap_content"> -</LinearLayout> +<View xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginStart="24dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="0dp" + android:layout_marginBottom="20dp" + android:background="?android:attr/dividerHorizontal" /> diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml index fa07eb1b105c..7ca3b954fcf9 100644 --- a/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml @@ -16,7 +16,7 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content"> -</LinearLayout> + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml index 77b12641c8c6..f73ee1532ba3 100644 --- a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml @@ -14,25 +14,35 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/keyboard_shortcuts_wrapper" - android:layout_width="488dp" + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="488dp" + android:layout_height="wrap_content"> + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:focusable="true"> - <ScrollView + android:orientation="vertical"> + <ScrollView android:id="@+id/keyboard_shortcuts_scroll_view" - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="1"> - <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <LinearLayout android:id="@+id/keyboard_shortcuts_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"/> - </ScrollView> - <View + </ScrollView> + <!-- Required for stretching to full available height when the items in the scroll view + occupy less space then the full height --> + <View android:layout_width="match_parent" - android:layout_height="1dp" - android:background="?android:attr/listDivider"/> -</LinearLayout> + android:layout_height="0dp" + android:layout_weight="1"/> + </LinearLayout> + <View + android:layout_gravity="bottom" + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="?android:attr/dividerHorizontal"/> +</FrameLayout> diff --git a/packages/SystemUI/res/layout/qs_add_tile_layout.xml b/packages/SystemUI/res/layout/qs_add_tile_layout.xml deleted file mode 100644 index 962b00e88b99..000000000000 --- a/packages/SystemUI/res/layout/qs_add_tile_layout.xml +++ /dev/null @@ -1,43 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - 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. ---> - -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:paddingTop="20dp" - android:paddingStart="7dp" - android:paddingEnd="7dp"> - <LinearLayout - android:layout_height="wrap_content" - android:layout_width="80dp" - android:orientation="vertical"> - <ImageView - android:id="@+id/tile_icon" - android:layout_gravity="center" - android:layout_width="@dimen/qs_tile_icon_size" - android:layout_height="@dimen/qs_tile_icon_size" /> - <TextView - android:id="@+id/tile_label" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center|bottom" - android:paddingTop="10dp" - android:gravity="center" - android:textSize="@dimen/qs_tile_text_size" /> - </LinearLayout> -</FrameLayout> diff --git a/packages/SystemUI/res/layout/qs_customize_layout.xml b/packages/SystemUI/res/layout/qs_customize_divider.xml index 0b8e02fb3564..71ad85bf3a96 100644 --- a/packages/SystemUI/res/layout/qs_customize_layout.xml +++ b/packages/SystemUI/res/layout/qs_customize_divider.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - 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,18 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.systemui.qs.customize.NonPagedTileLayout + +<TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/tiles_container" + android:id="@android:id/title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical"> - - <view - class="com.android.systemui.qs.PagedTileLayout$TilePage" - android:id="@+id/tile_page" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - -</com.android.systemui.qs.customize.NonPagedTileLayout> - + android:paddingTop="20dp" + android:paddingStart="16dp" + android:paddingEnd="8dp" + android:paddingBottom="13dp" + android:textAppearance="@android:style/TextAppearance.Material.Body2" + android:textColor="?android:attr/colorAccent" + android:text="@string/drag_to_add_tiles" /> diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml index e56431b012e7..73a92d905a3d 100644 --- a/packages/SystemUI/res/layout/qs_customize_panel.xml +++ b/packages/SystemUI/res/layout/qs_customize_panel.xml @@ -22,85 +22,53 @@ android:background="@drawable/qs_customizer_background" android:gravity="center_horizontal"> - <FrameLayout + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/notification_header_bg"> + android:paddingTop="28dp" + android:paddingEnd="8dp"> - <LinearLayout - android:id="@+id/drag_buttons" - android:layout_width="match_parent" - android:layout_height="fill_parent" - android:orientation="horizontal"> - <FrameLayout - android:layout_width="0dp" - android:layout_height="fill_parent" - android:layout_weight="1"> - <com.android.systemui.qs.customize.DropButton - android:id="@+id/info_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:gravity="center" - android:drawableStart="@drawable/ic_info" - android:drawablePadding="10dp" - android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="@android:color/white" - android:text="@string/qs_customize_info" /> - </FrameLayout> - <FrameLayout - android:layout_width="0dp" - android:layout_height="fill_parent" - android:layout_weight="1"> - <com.android.systemui.qs.customize.DropButton - android:id="@+id/remove_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:gravity="center" - android:drawableStart="@drawable/ic_close_white" - android:drawablePadding="10dp" - android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="@android:color/white" - android:text="@string/qs_customize_remove" /> - </FrameLayout> - </LinearLayout> + <ImageView + android:id="@+id/close" + android:layout_width="56dp" + android:layout_height="56dp" + android:padding="16dp" + android:src="@drawable/ic_close_white" /> - <Toolbar - android:id="@*android:id/action_bar" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:navigationContentDescription="@*android:string/action_bar_up_description" - android:background="@drawable/notification_header_bg" - style="?android:attr/toolbarStyle" /> - </FrameLayout> + <Space + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1" /> - <com.android.systemui.tuner.AutoScrollView - android:layout_width="@dimen/notification_panel_width" - android:layout_height="0dp" - android:layout_weight="1" - android:paddingTop="12dp" - android:paddingBottom="8dp" - android:elevation="2dp"> + <Button + android:id="@+id/save" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingStart="12dp" + android:paddingEnd="12dp" + android:background="?android:attr/selectableItemBackground" + android:textAppearance="@android:style/TextAppearance.Material.Widget.Button.Inverse" + android:textColor="?android:attr/colorAccent" + android:text="@string/save" /> - <com.android.systemui.qs.customize.CustomQSPanel - android:id="@+id/quick_settings_panel" - android:background="#0000" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> + <Button + android:id="@+id/reset" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingStart="12dp" + android:paddingEnd="12dp" + android:background="?android:attr/selectableItemBackground" + android:textAppearance="@android:style/TextAppearance.Material.Widget.Button.Inverse" + android:textColor="?android:attr/colorAccent" + android:text="@*android:string/reset" /> - </com.android.systemui.tuner.AutoScrollView> + </LinearLayout> - <com.android.systemui.qs.customize.FloatingActionButton - android:id="@+id/fab" - android:clickable="true" - android:layout_width="@dimen/fab_size" - android:layout_height="@dimen/fab_size" - android:layout_gravity="bottom|end" - android:layout_marginEnd="@dimen/fab_margin" - android:layout_marginBottom="@dimen/fab_margin" - android:elevation="@dimen/fab_elevation" - android:background="@drawable/fab_background" /> + <android.support.v7.widget.RecyclerView + android:id="@android:id/list" + android:layout_width="@dimen/notification_panel_width" + android:layout_height="0dp" + android:layout_weight="1" /> <View android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/qs_customize_tile_frame.xml b/packages/SystemUI/res/layout/qs_customize_tile_frame.xml new file mode 100644 index 000000000000..aaa84fd86d08 --- /dev/null +++ b/packages/SystemUI/res/layout/qs_customize_tile_frame.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:paddingStart="8dp" + android:paddingEnd="8dp" + android:paddingBottom="16dp" /> diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml index 5a96dc3bd01e..153e35f1f675 100644 --- a/packages/SystemUI/res/layout/qs_detail_header.xml +++ b/packages/SystemUI/res/layout/qs_detail_header.xml @@ -18,10 +18,20 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_alignParentBottom="true" - android:padding="@dimen/qs_panel_padding" + android:paddingEnd="@dimen/qs_panel_padding" android:visibility="invisible" - android:background="@drawable/btn_borderless_rect" > + android:background="@drawable/btn_borderless_rect" + android:gravity="center"> + + <ImageView + android:id="@*android:id/up" + android:layout_width="56dp" + android:layout_height="56dp" + android:layout_marginEnd="16dp" + android:padding="16dp" + android:clickable="true" + android:background="?android:attr/selectableItemBackground" + android:src="?android:attr/homeAsUpIndicator" /> <TextView android:id="@android:id/title" @@ -37,4 +47,4 @@ android:clickable="false" android:textAppearance="@style/TextAppearance.QS.DetailHeader" /> -</com.android.keyguard.AlphaOptimizedLinearLayout>
\ No newline at end of file +</com.android.keyguard.AlphaOptimizedLinearLayout> diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml index ccdddf7a0a59..5bb4f5d04019 100644 --- a/packages/SystemUI/res/layout/qs_detail_item.xml +++ b/packages/SystemUI/res/layout/qs_detail_item.xml @@ -28,7 +28,7 @@ android:id="@android:id/icon" android:layout_width="24dp" android:layout_height="24dp" - android:layout_marginEnd="12dp" /> + android:layout_marginEnd="20dp" /> <LinearLayout android:layout_width="0dp" diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml index 0bef513af659..5fde4f696979 100644 --- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml +++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml @@ -15,6 +15,7 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:layout_height="48dp" android:paddingLeft="16dp" android:paddingRight="16dp" style="@style/BrightnessDialogContainer"> diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index 6784695e5a99..07ac6a58e351 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -106,7 +106,7 @@ <LinearLayout android:id="@+id/date_time_group" android:layout_width="wrap_content" - android:layout_height="28dp" + android:layout_height="25dp" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:orientation="horizontal"> @@ -115,7 +115,7 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_marginStart="16dp" - android:layout_marginTop="2dp" + android:layout_marginTop="4dp" android:id="@+id/clock" /> <com.android.systemui.statusbar.policy.DateView @@ -123,7 +123,7 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_marginStart="6dp" - android:layout_marginTop="8dp" + android:layout_marginTop="4dp" android:drawableStart="@drawable/header_dot" android:drawablePadding="6dp" android:singleLine="true" @@ -136,7 +136,7 @@ android:id="@+id/alarm_status" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_marginTop="8dp" + android:layout_marginTop="4dp" android:drawablePadding="6dp" android:drawableStart="@drawable/ic_access_alarms_small" android:textColor="#64ffffff" @@ -152,9 +152,9 @@ android:background="#0000" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="30dp" - android:layout_marginStart="8dp" - android:layout_marginEnd="8dp" + android:layout_marginTop="25dp" + android:layout_marginStart="12dp" + android:layout_marginEnd="12dp" android:layout_alignParentEnd="true" android:clipChildren="false" android:clipToPadding="false" /> @@ -164,7 +164,7 @@ layout="@layout/qs_detail_header" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_alignParentBottom="true" + android:layout_marginTop="28dp" /> <com.android.systemui.statusbar.AlphaOptimizedImageView diff --git a/packages/SystemUI/res/layout/status_bar_no_notifications.xml b/packages/SystemUI/res/layout/status_bar_no_notifications.xml index dd501d4861eb..6f87184498d5 100644 --- a/packages/SystemUI/res/layout/status_bar_no_notifications.xml +++ b/packages/SystemUI/res/layout/status_bar_no_notifications.xml @@ -25,9 +25,9 @@ android:id="@+id/no_notifications" android:layout_width="match_parent" android:layout_height="64dp" - android:paddingTop="12dp" + android:paddingTop="28dp" android:gravity="top|center_horizontal" - android:textColor="#ffffff" - android:textSize="20sp" + android:textColor="#e6ffffff" + android:textSize="16sp" android:text="@string/empty_shade_text"/> </com.android.systemui.statusbar.EmptyShadeView> diff --git a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml index dc7577af29ee..efb273f8692d 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml @@ -19,15 +19,16 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:visibility="gone" - android:clipChildren="false" - android:clipToPadding="false"> + android:paddingEnd="8dp" + android:visibility="gone"> <com.android.systemui.statusbar.DismissViewButton + style="@android:style/Widget.Material.Button.Borderless" android:id="@+id/dismiss_text" - android:layout_width="48dp" - android:layout_height="48dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="end" android:focusable="true" - android:background="@drawable/ripple_drawable" - android:contentDescription="@string/accessibility_clear_all"/> + android:contentDescription="@string/accessibility_clear_all" + android:text="@string/clear_all_notifications_text" + android:textAllCaps="true"/> </com.android.systemui.statusbar.DismissView> diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml index e0affa177897..43e7bacd3d41 100644 --- a/packages/SystemUI/res/values-land/config.xml +++ b/packages/SystemUI/res/values-land/config.xml @@ -38,6 +38,4 @@ while the stack is not focused. --> <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item> <item name="recents_layout_unfocused_range_max" format="float" type="integer">1.5</item> - - <integer name="quick_settings_num_columns">4</integer> </resources> diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index c75a89fa4b31..26a81c8d835c 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -19,8 +19,7 @@ <!-- thickness (width) of the navigation bar on phones that require it --> <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_width</dimen> - <!-- Standard notification width + gravity --> - <dimen name="notification_panel_width">@dimen/standard_notification_panel_width</dimen> + <!-- Standard notification gravity --> <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer> <dimen name="docked_divider_handle_width">2dp</dimen> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 71f92fd18587..c0652d8a8e8b 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -93,4 +93,6 @@ <dimen name="navigation_key_width">128dp</dimen> <dimen name="navigation_key_padding">25dp</dimen> + + <dimen name="qs_expand_margin">0dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-w550dp-land/config.xml b/packages/SystemUI/res/values-w550dp-land/config.xml new file mode 100644 index 000000000000..71e54a1ca61c --- /dev/null +++ b/packages/SystemUI/res/values-w550dp-land/config.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2016, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources> + <integer name="quick_settings_num_columns">4</integer> +</resources> diff --git a/packages/SystemUI/res/values-w550dp-land/dimens.xml b/packages/SystemUI/res/values-w550dp-land/dimens.xml new file mode 100644 index 000000000000..4160c83683cc --- /dev/null +++ b/packages/SystemUI/res/values-w550dp-land/dimens.xml @@ -0,0 +1,23 @@ +<?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. +*/ +--> +<resources> + <!-- Standard notification width + gravity --> + <dimen name="notification_panel_width">544dp</dimen> + + <dimen name="qs_expand_margin">32dp</dimen> +</resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 9bb6dc6abb75..a9b8df2934c7 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -158,5 +158,4 @@ <!-- Keyboard shortcuts colors --> <color name="ksh_system_group_color">#ff00bcd4</color> <color name="ksh_application_group_color">#fff44336</color> - <color name="ksh_dialog_background_color">#ffffffff</color> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index e8df01b19415..083707af3f7b 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -138,12 +138,6 @@ <!-- The duration in seconds to wait before the dismiss buttons are shown. --> <integer name="recents_task_bar_dismiss_delay_seconds">1000</integer> - <!-- The duration of the window transition when coming to Recents from an app. - In order to defer the in-app animations until after the transition is complete, - we also need to use this value as the starting delay when animating the first - task decorations in. --> - <integer name="recents_enter_from_app_transition_duration">325</integer> - <!-- The duration for animating the task decorations in after transitioning from an app. --> <integer name="recents_task_enter_from_app_duration">200</integer> @@ -153,12 +147,6 @@ <!-- The duration for animating the task decorations out before transitioning to an app. --> <integer name="recents_task_exit_to_app_duration">125</integer> - <!-- The duration of the window transition when coming to Recents from the Launcher. - In order to defer the in-app animations until after the transition is complete, - we also need to use this value as the starting delay when animating the task views - in from the bottom of the screen. --> - <integer name="recents_enter_from_home_transition_duration">100</integer> - <!-- The min animation duration for animating the nav bar scrim in. --> <integer name="recents_nav_bar_scrim_enter_duration">400</integer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 32d09e81b870..e5e5710cd68a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -124,7 +124,7 @@ <dimen name="close_handle_underlap">32dp</dimen> <!-- Height of the status bar header bar --> - <dimen name="status_bar_header_height">90dp</dimen> + <dimen name="status_bar_header_height">80dp</dimen> <!-- Height of the status bar header bar when expanded --> <dimen name="status_bar_header_height_expanded">116dp</dimen> @@ -186,6 +186,7 @@ <dimen name="qs_detail_empty_text_size">14sp</dimen> <dimen name="qs_data_usage_text_size">14sp</dimen> <dimen name="qs_data_usage_usage_text_size">36sp</dimen> + <dimen name="qs_expand_margin">0dp</dimen> <dimen name="segmented_button_spacing">0dp</dimen> <dimen name="borderless_button_radius">2dp</dimen> @@ -606,4 +607,7 @@ <dimen name="docked_divider_handle_width">16dp</dimen> <dimen name="docked_divider_handle_height">2dp</dimen> + + <dimen name="battery_height">14.5dp</dimen> + <dimen name="battery_width">9.5dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index c6c448d0c449..6ff9be14b3ce 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1044,9 +1044,6 @@ <!-- VolumeUI restoration notification: text --> <string name="volumeui_notification_text">Touch to restore the original.</string> - <!-- Describes the way 2 names are concatenated. An example would be ", " to produce "Peter Muller, Paul Curry". Please also include a space here if it's appropriate in the language and if it's a RTL language include it on the left. The translation should start and end with " to keep the white space if desired [CHAR LIMIT=5] --> - <string name="group_summary_concadenation">", "</string> - <!-- Toast shown when user unlocks screen and managed profile activity is in the foreground --> <string name="managed_profile_foreground_toast">You\'re using your work profile</string> @@ -1187,6 +1184,11 @@ <!-- Description for the toggle to set the initial scroll state to be paging or stack. DO NOT TRANSLATE --> <string name="overview_initial_state_paging_desc">Determines whether Overview will initially be in a stacked or paged state</string> + <!-- Toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=60]--> + <string name="overview_nav_bar_gesture">Enable split-screen swipe-up accelerator</string> + <!-- Description for the toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=NONE]--> + <string name="overview_nav_bar_gesture_desc">Enable gesture to enter split-screen by swiping up from the Overview button</string> + <!-- Category in the System UI Tuner settings, where new/experimental settings are --> <string name="experimental">Experimental</string> @@ -1400,4 +1402,7 @@ <!-- SysUI Tuner: Label for preview area in navigation bar tuner [CHAR LIMIT=NONE] --> <string name="preview">Preview</string> + <!-- Label for area where tiles can be dragged out of [CHAR LIMIT=60] --> + <string name="drag_to_add_tiles">Drag to add tiles</string> + </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 9931ab97f938..60a9fc233aa3 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -16,10 +16,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <style name="RecentsStyle" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar"> - <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item> - </style> - <style name="RecentsTheme" parent="@android:style/Theme.Material"> <!-- NoTitle --> <item name="android:windowNoTitle">true</item> @@ -27,38 +23,23 @@ <item name="android:statusBarColor">@android:color/transparent</item> <item name="android:navigationBarColor">@android:color/transparent</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item> - <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item> + <item name="android:windowAnimationStyle">@null</item> <item name="android:ambientShadowAlpha">0.35</item> </style> - <!-- Alternate Recents theme --> + <!-- Recents theme --> <style name="RecentsTheme.Wallpaper"> - <!-- Wallpaper --> <item name="android:windowBackground">@color/transparent</item> <item name="android:colorBackgroundCacheHint">@null</item> <item name="android:windowShowWallpaper">true</item> </style> - <!-- Performance optimized alternate Recents theme (no wallpaper) --> + <!-- Performance optimized Recents theme (no wallpaper) --> <style name="RecentsTheme.NoWallpaper"> <item name="android:windowBackground">@android:color/black</item> </style> - <!-- Animations for a non-full-screen window or activity. --> - <style name="Animation.RecentsActivity" parent="@android:style/Animation.Activity"> - <item name="android:activityOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item> - <item name="android:activityOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item> - <item name="android:taskOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item> - <item name="android:taskOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item> - <item name="android:taskToFrontEnterAnimation">@anim/recents_launch_from_launcher_enter</item> - <item name="android:taskToFrontExitAnimation">@anim/recents_launch_from_launcher_exit</item> - <item name="android:wallpaperOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item> - <item name="android:wallpaperOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item> - <item name="android:wallpaperIntraOpenEnterAnimation">@anim/wallpaper_recents_launch_from_launcher_enter</item> - <item name="android:wallpaperIntraOpenExitAnimation">@anim/wallpaper_recents_launch_from_launcher_exit</item> - </style> - <style name="TextAppearance.StatusBar.HeadsUp" parent="@*android:style/TextAppearance.StatusBar"> </style> @@ -241,6 +222,10 @@ parent="@*android:style/TextAppearance.Material.Notification.Info"> </style> + <style name="TextAppearance.Material.Notification.HybridNotificationDivider" + parent="@*android:style/TextAppearance.Material.Notification"> + </style> + <style name="SearchPanelCircle"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">match_parent</item> diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml index febe5188cf88..4de4cede0faa 100644 --- a/packages/SystemUI/res/xml/tuner_prefs.xml +++ b/packages/SystemUI/res/xml/tuner_prefs.xml @@ -122,6 +122,11 @@ android:title="@string/overview_fast_toggle_via_button" android:summary="@string/overview_fast_toggle_via_button_desc" /> + <com.android.systemui.tuner.TunerSwitch + android:key="overview_nav_bar_gesture" + android:title="@string/overview_nav_bar_gesture" + android:summary="@string/overview_nav_bar_gesture_desc" /> + </PreferenceScreen> <SwitchPreference diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java index a0dbad440c9b..e770b5d89a0b 100755 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java @@ -51,6 +51,8 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction private final int[] mColors; + private final int mIntrinsicWidth; + private final int mIntrinsicHeight; private boolean mShowPercent; private float mButtonHeightFraction; @@ -161,6 +163,19 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode, mLightModeBackgroundColor = context.getColor(R.color.light_mode_icon_color_dual_tone_background); mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill); + + mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width); + mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height); + } + + @Override + public int getIntrinsicHeight() { + return mIntrinsicHeight; + } + + @Override + public int getIntrinsicWidth() { + return mIntrinsicWidth; } public void startListening() { diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java index cd6dce01e48e..5e33a9f84cac 100644 --- a/packages/SystemUI/src/com/android/systemui/Interpolators.java +++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java @@ -34,4 +34,10 @@ public class Interpolators { public static final Interpolator LINEAR = new LinearInterpolator(); public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator(); public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f); + + /** + * Interpolator to be used when animating a move based on a click. Pair with enough duration. + */ + public static final Interpolator TOUCH_RESPONSE = + new PathInterpolator(0.3f, 0f, 0.1f, 1f); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java index ed909040c5f1..1df372bc6f5e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java @@ -24,6 +24,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; +import android.widget.ImageView.ScaleType; import com.android.systemui.R; import java.util.Objects; @@ -96,7 +97,7 @@ public class QSIconView extends ViewGroup { protected View createIcon() { final ImageView icon = new ImageView(mContext); icon.setId(android.R.id.icon); - icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + icon.setScaleType(ScaleType.FIT_CENTER); return icon; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index 35000d3c3f11..d79f4d4d0e26 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -76,7 +76,7 @@ public abstract class QSTile<TState extends State> implements Listenable { private String mTileSpec; - abstract protected TState newTileState(); + public abstract TState newTileState(); abstract protected void handleClick(); abstract protected void handleUpdateState(TState state, Object arg); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 753efb0e05a8..f208470a2927 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -18,12 +18,13 @@ package com.android.systemui.qs; import android.content.Context; import android.content.res.ColorStateList; +import android.content.res.Configuration; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; - +import android.widget.Space; import com.android.systemui.R; import java.util.ArrayList; @@ -102,6 +103,8 @@ public class QuickQSPanel extends QSPanel { private static class HeaderTileLayout extends LinearLayout implements QSTileLayout { + private final ImageView mDownArrow; + public HeaderTileLayout(Context context) { super(context); setClipChildren(false); @@ -111,23 +114,40 @@ public class QuickQSPanel extends QSPanel { int padding = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding); - ImageView downArrow = new ImageView(context); - downArrow.setImageResource(R.drawable.ic_expand_more); - downArrow.setImageTintList(ColorStateList.valueOf(context.getResources().getColor( + mDownArrow = new ImageView(context); + mDownArrow.setImageResource(R.drawable.ic_expand_more); + mDownArrow.setImageTintList(ColorStateList.valueOf(context.getResources().getColor( android.R.color.white, null))); - downArrow.setLayoutParams(generateLayoutParams()); - downArrow.setPadding(padding, padding, padding, padding); - addView(downArrow); + mDownArrow.setLayoutParams(generateLayoutParams()); + mDownArrow.setPadding(padding, padding, padding, padding); + updateDownArrowMargin(); + addView(mDownArrow); setOrientation(LinearLayout.HORIZONTAL); } @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + updateDownArrowMargin(); + } + + private void updateDownArrowMargin() { + LayoutParams params = (LayoutParams) mDownArrow.getLayoutParams(); + params.setMarginStart(mContext.getResources().getDimensionPixelSize( + R.dimen.qs_expand_margin)); + mDownArrow.setLayoutParams(params); + } + + @Override public void addTile(TileRecord tile) { - tile.tileView.setLayoutParams(generateLayoutParams()); - addView(tile.tileView, getChildCount() - 1 /* Leave icon at end */); + addView(tile.tileView, getChildCount() - 1 /* Leave icon at end */, + generateLayoutParams()); + // Add a spacer. + addView(new Space(mContext), getChildCount() - 1 /* Leave icon at end */, + generateSpaceParams()); } - private LayoutParams generateLayoutParams() { + private LayoutParams generateSpaceParams() { int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size); LayoutParams lp = new LayoutParams(0, size); lp.weight = 1; @@ -135,9 +155,30 @@ public class QuickQSPanel extends QSPanel { return lp; } + private LayoutParams generateLayoutParams() { + int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size); + LayoutParams lp = new LayoutParams(size, size); + lp.gravity = Gravity.CENTER; + return lp; + } + @Override public void removeTile(TileRecord tile) { - removeView(tile.tileView); + int childIndex = getChildIndex(tile.tileView); + // Remove the tile. + removeViewAt(childIndex); + // Remove its spacer as well. + removeViewAt(childIndex); + } + + private int getChildIndex(QSTileBaseView tileView) { + final int N = getChildCount(); + for (int i = 0; i < N; i++) { + if (getChildAt(i) == tileView) { + return i; + } + } + return -1; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java deleted file mode 100644 index 36bed0d25c19..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.qs.customize; - -import android.content.ComponentName; -import android.content.pm.PackageManager; -import android.content.pm.ServiceInfo; -import android.graphics.drawable.Drawable; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; -import com.android.systemui.R; -import com.android.systemui.qs.QSTile; - -public class BlankCustomTile extends QSTile<QSTile.State> { - public static final String PREFIX = "custom("; - - private final ComponentName mComponent; - - private BlankCustomTile(Host host, String action) { - super(host); - mComponent = ComponentName.unflattenFromString(action); - } - - public static QSTile<?> create(Host host, String spec) { - if (spec == null || !spec.startsWith(PREFIX) || !spec.endsWith(")")) { - throw new IllegalArgumentException("Bad custom tile spec: " + spec); - } - final String action = spec.substring(PREFIX.length(), spec.length() - 1); - if (action.isEmpty()) { - throw new IllegalArgumentException("Empty custom tile spec action"); - } - return new BlankCustomTile(host, action); - } - - @Override - public void setListening(boolean listening) { - } - - @Override - protected State newTileState() { - return new State(); - } - - @Override - protected void handleUserSwitch(int newUserId) { - super.handleUserSwitch(newUserId); - } - - @Override - protected void handleClick() { - MetricsLogger.action(mContext, getMetricsCategory(), mComponent.getPackageName()); - } - - @Override - protected void handleLongClick() { - } - - @Override - protected void handleUpdateState(State state, Object arg) { - try { - PackageManager pm = mContext.getPackageManager(); - ServiceInfo info = pm.getServiceInfo(mComponent, 0); - Drawable drawable = info.loadIcon(pm); - drawable.setTint(mContext.getColor(R.color.qs_tile_tint_active)); - state.icon = new DrawableIcon(drawable); - state.label = info.loadLabel(pm).toString(); - state.contentDescription = state.label; - } catch (Exception e) { - } - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.QS_INTENT; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java deleted file mode 100644 index 286748b17255..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.systemui.qs.customize; - -import android.app.ActivityManager; -import android.content.ClipData; -import android.content.Context; -import android.content.Intent; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings.Secure; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; - -import com.android.systemui.R; -import com.android.systemui.qs.QSPanel; -import com.android.systemui.qs.QSTile; -import com.android.systemui.qs.external.CustomTile; -import com.android.systemui.qs.external.TileLifecycleManager; -import com.android.systemui.statusbar.phone.QSTileHost; -import com.android.systemui.tuner.TunerService; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * A version of QSPanel that allows tiles to be dragged around rather than - * clicked on. Dragging starting and receiving is handled in the NonPagedTileLayout, - * and the saving/ordering is handled by the CustomQSTileHost. - */ -public class CustomQSPanel extends QSPanel { - - private static final String TAG = "CustomQSPanel"; - private static final boolean DEBUG = false; - - private List<String> mSavedTiles = Collections.emptyList(); - private ArrayList<String> mStash; - private List<String> mTiles = new ArrayList<>(); - - private ArrayList<QSTile<?>> mCurrentTiles = new ArrayList<>(); - - public CustomQSPanel(Context context, AttributeSet attrs) { - super(context, attrs); - mTileLayout = (QSTileLayout) LayoutInflater.from(mContext) - .inflate(R.layout.qs_customize_layout, mQsContainer, false); - mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */); - ((NonPagedTileLayout) mTileLayout).setCustomQsPanel(this); - removeView(mFooter.getView()); - - if (DEBUG) Log.d(TAG, "new CustomQSPanel", new Throwable()); - TunerService.get(mContext).addTunable(this, QSTileHost.TILES_SETTING); - } - - @Override - protected void showDetail(boolean show, Record r) { - // No detail here. - } - - @Override - protected void onDetachedFromWindow() { - // Don't allow the super to unregister the tunable. - } - - @Override - public void onTuningChanged(String key, String newValue) { - if (key.equals(QS_SHOW_BRIGHTNESS)) { - // No Brightness for you. - super.onTuningChanged(key, "0"); - } - if (QSTileHost.TILES_SETTING.equals(key)) { - mSavedTiles = Collections.unmodifiableList( - QSTileHost.loadTileSpecs(mContext, newValue)); - if (DEBUG) Log.d(TAG, "New saved tiles " + TextUtils.join(",", mSavedTiles)); - } - } - - @Override - protected void createCustomizePanel() { - // Already in CustomizePanel. - } - - public void tileSelected(QSTile<?> tile, ClipData currentClip) { - String sourceSpec = getSpec(currentClip); - String destSpec = tile.getTileSpec(); - if (!sourceSpec.equals(destSpec)) { - moveTo(sourceSpec, destSpec); - } - } - - public ClipData getClip(QSTile<?> tile) { - String tileSpec = tile.getTileSpec(); - // TODO: Something better than plain text. - // TODO: Once using something better than plain text, stop listening to non-QS drag events. - return ClipData.newPlainText(tileSpec, tileSpec); - } - - public String getSpec(ClipData data) { - return data.getItemAt(0).getText().toString(); - } - - public void setSavedTiles() { - if (DEBUG) Log.d(TAG, "setSavedTiles " + TextUtils.join(",", mSavedTiles)); - setTiles(mSavedTiles); - } - - public void saveCurrentTiles() { - mHost.changeTiles(mSavedTiles, mTiles); - } - - public void stashCurrentTiles() { - mStash = new ArrayList<>(mTiles); - } - - public void unstashTiles() { - setTiles(mStash); - } - - @Override - public void setTiles(Collection<QSTile<?>> tiles) { - setTilesInternal(); - } - - private void setTilesInternal() { - if (DEBUG) Log.d(TAG, "Set tiles internal"); - for (int i = 0; i < mCurrentTiles.size(); i++) { - mCurrentTiles.get(i).destroy(); - } - mCurrentTiles.clear(); - for (int i = 0; i < mTiles.size(); i++) { - if (mTiles.get(i).startsWith(CustomTile.PREFIX)) { - QSTile<?> tile = BlankCustomTile.create(mHost, mTiles.get(i)); - tile.setTileSpec(mTiles.get(i)); - mCurrentTiles.add(tile); - } else { - QSTile<?> tile = mHost.createTile(mTiles.get(i)); - if (tile != null) { - tile.setTileSpec(mTiles.get(i)); - mCurrentTiles.add(tile); - } else { - if (DEBUG) Log.d(TAG, "Skipping " + mTiles.get(i)); - } - } - } - super.setTiles(mCurrentTiles); - } - - public void addTile(String spec) { - if (DEBUG) Log.d(TAG, "addTile " + spec); - mTiles.add(spec); - setTilesInternal(); - } - - public void moveTo(String from, String to) { - if (DEBUG) Log.d(TAG, "moveTo " + from + " " + to); - int fromIndex = mTiles.indexOf(from); - if (fromIndex < 0) { - Log.e(TAG, "Unknown from tile " + from); - return; - } - int index = mTiles.indexOf(to); - if (index < 0) { - Log.e(TAG, "Unknown to tile " + to); - return; - } - mTiles.remove(fromIndex); - mTiles.add(index, from); - setTilesInternal(); - } - - public void remove(String spec) { - if (!mTiles.remove(spec)) { - Log.e(TAG, "Unknown remove spec " + spec); - } - setTilesInternal(); - } - - public void setTiles(List<String> tiles) { - if (DEBUG) Log.d(TAG, "Set tiles " + TextUtils.join(",", tiles)); - mTiles = new ArrayList<>(tiles); - setTilesInternal(); - } - - public Collection<QSTile<?>> getTiles() { - return mCurrentTiles; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/DropButton.java b/packages/SystemUI/src/com/android/systemui/qs/customize/DropButton.java deleted file mode 100644 index 313540809e0d..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/DropButton.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package com.android.systemui.qs.customize; - -import android.content.ClipData; -import android.content.Context; -import android.util.AttributeSet; -import android.view.DragEvent; -import android.view.View; -import android.view.View.OnDragListener; -import android.widget.TextView; - -public class DropButton extends TextView implements OnDragListener { - - private OnDropListener mListener; - - public DropButton(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - // TODO: Don't do this, instead make this view the right size... - ((View) getParent()).setOnDragListener(this); - } - - public void setOnDropListener(OnDropListener listener) { - mListener = listener; - } - - private void setHovering(boolean hovering) { - setAlpha(hovering ? .3f : 1); - } - - @Override - public boolean onDrag(View v, DragEvent event) { - switch (event.getAction()) { - case DragEvent.ACTION_DRAG_ENTERED: - setHovering(true); - break; - case DragEvent.ACTION_DROP: - if (mListener != null) { - mListener.onDrop(this, event.getClipData()); - } - case DragEvent.ACTION_DRAG_EXITED: - case DragEvent.ACTION_DRAG_ENDED: - setHovering(false); - break; - } - return true; - } - - public interface OnDropListener { - void onDrop(View v, ClipData data); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/FloatingActionButton.java b/packages/SystemUI/src/com/android/systemui/qs/customize/FloatingActionButton.java deleted file mode 100644 index 8791a1007adc..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/FloatingActionButton.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.qs.customize; - -import android.animation.AnimatorInflater; -import android.content.Context; -import android.graphics.Outline; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewOutlineProvider; -import android.widget.ImageView; - -import com.android.systemui.R; - -public class FloatingActionButton extends ImageView { - - public FloatingActionButton(Context context, AttributeSet attrs) { - super(context, attrs); - setScaleType(ScaleType.CENTER); - setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, R.anim.fab_elevation)); - setOutlineProvider(new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - outline.setOval(0, 0, getWidth(), getHeight()); - } - }); - setClipToOutline(true); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - invalidateOutline(); - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java deleted file mode 100644 index 98c7be414748..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.systemui.qs.customize; - -import android.content.ClipData; -import android.content.Context; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.view.DragEvent; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.widget.LinearLayout; - -import com.android.systemui.R; -import com.android.systemui.qs.PagedTileLayout; -import com.android.systemui.qs.PagedTileLayout.TilePage; -import com.android.systemui.qs.QSPanel.QSTileLayout; -import com.android.systemui.qs.QSPanel.TileRecord; -import com.android.systemui.qs.QSTile; - -import java.util.ArrayList; - -/** - * Similar to PagedTileLayout, except that instead of pages it lays them out - * vertically and expects to be inside a ScrollView. - * @see CustomQSPanel - */ -public class NonPagedTileLayout extends LinearLayout implements QSTileLayout, OnTouchListener { - - private final ArrayList<TilePage> mPages = new ArrayList<>(); - private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>(); - private CustomQSPanel mPanel; - private final Rect mHitRect = new Rect(); - - private ClipData mCurrentClip; - private View mCurrentView; - - public NonPagedTileLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - TilePage page = (PagedTileLayout.TilePage) findViewById(R.id.tile_page); - page.setMaxRows(3 /* First page only gets 3 */); - mPages.add(page); - } - - public void setCustomQsPanel(CustomQSPanel qsPanel) { - mPanel = qsPanel; - } - - @Override - public void addTile(TileRecord record) { - mTiles.add(record); - distributeTiles(); - if (record.tileView.getTag() == record.tile) { - return; - } - record.tileView.setTag(record.tile); - record.tileView.setVisibility(View.VISIBLE); - record.tileView.init(null, null); - record.tileView.setOnTouchListener(this); - if (mCurrentClip != null && mCurrentClip.getItemAt(0) - .getText().toString().equals(record.tile.getTileSpec())) { - record.tileView.setAlpha(.3f); - mCurrentView = record.tileView; - } - } - - @Override - public void removeTile(TileRecord tile) { - if (mTiles.remove(tile)) { - distributeTiles(); - } - } - - private void distributeTiles() { - final int NP = mPages.size(); - for (int i = 0; i < NP; i++) { - mPages.get(i).removeAllViews(); - } - int index = 0; - final int NT = mTiles.size(); - for (int i = 0; i < NT; i++) { - TileRecord tile = mTiles.get(i); - mPages.get(index).addTile(tile); - // Keep everything in one layout for now. - if (false && mPages.get(index).isFull()) { - if (++index == mPages.size()) { - LayoutInflater inflater = LayoutInflater.from(mContext); - inflater.inflate(R.layout.horizontal_divider, this); - mPages.add((TilePage) inflater.inflate(R.layout.qs_paged_page, this, false)); - addView(mPages.get(mPages.size() - 1)); - } - } - } - } - - @Override - public int getOffsetTop(TileRecord tile) { - // No touch feedback, so this isn't required. - return 0; - } - - @Override - public boolean updateResources() { - return false; - } - - @Override - public boolean onDragEvent(DragEvent event) { - switch (event.getAction()) { - case DragEvent.ACTION_DRAG_LOCATION: - float x = event.getX(); - float y = event.getY(); - final int NP = mPages.size(); - for (int i = 0; i < NP; i++) { - TilePage page = mPages.get(i); - if (contains(page, x, y)) { - x -= page.getLeft(); - y -= page.getTop(); - final int NC = page.getChildCount(); - for (int j = 0; j < NC; j++) { - View child = page.getChildAt(j); - if (contains(child, x, y)) { - mPanel.tileSelected((QSTile<?>) child.getTag(), mCurrentClip); - } - } - break; - } - } - break; - case DragEvent.ACTION_DRAG_ENDED: - onDragEnded(); - break; - } - return true; - } - - @Override - public boolean onTouch(View v, MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - // Stash the current tiles, in case the drop is on info, that we can restore - // the previous state. - mPanel.stashCurrentTiles(); - mCurrentView = v; - mCurrentClip = mPanel.getClip((QSTile<?>) v.getTag()); - View.DragShadowBuilder shadow = new View.DragShadowBuilder(v); - ((View) getParent().getParent()).startDrag(mCurrentClip, shadow, null, 0); - v.setAlpha(.3f); - return true; - } - return false; - } - - public void onDragEnded() { - mCurrentView.setAlpha(1f); - mCurrentView = null; - mCurrentClip = null; - } - - private boolean contains(View v, float x, float y) { - v.getHitRect(mHitRect); - return mHitRect.contains((int) x, (int) y); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index a6c7fe4ad92c..edcccaca2a14 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -16,38 +16,25 @@ package com.android.systemui.qs.customize; import android.animation.Animator; -import android.content.ClipData; +import android.animation.Animator.AnimatorListener; import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnDismissListener; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; import android.util.AttributeSet; -import android.util.Log; -import android.util.TypedValue; import android.view.ContextThemeWrapper; -import android.view.DragEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.WindowManager; import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.Toolbar; -import android.widget.Toolbar.OnMenuItemClickListener; - import com.android.systemui.R; import com.android.systemui.qs.QSDetailClipper; -import com.android.systemui.qs.QSTile.Host.Callback; -import com.android.systemui.qs.customize.DropButton.OnDropListener; -import com.android.systemui.qs.customize.TileAdapter.TileSelectedListener; +import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.phone.QSTileHost; -import com.android.systemui.statusbar.phone.SystemUIDialog; import java.util.ArrayList; +import java.util.List; /** * Allows full-screen customization of QS, through show() and hide(). @@ -55,26 +42,19 @@ import java.util.ArrayList; * This adds itself to the status bar window, so it can appear on top of quick settings and * *someday* do fancy animations to get into/out of it. */ -public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener, Callback, - OnDropListener, OnClickListener, Animator.AnimatorListener, TileSelectedListener, - OnCancelListener, OnDismissListener { +public class QSCustomizer extends LinearLayout implements AnimatorListener, OnClickListener { - private static final int MENU_SAVE = Menu.FIRST; - private static final int MENU_RESET = Menu.FIRST + 1; private final QSDetailClipper mClipper; private PhoneStatusBar mPhoneStatusBar; - private Toolbar mToolbar; - private ViewGroup mDragButtons; - private CustomQSPanel mQsPanel; - private boolean isShown; - private DropButton mInfoButton; - private DropButton mRemoveButton; - private FloatingActionButton mFab; - private SystemUIDialog mDialog; private QSTileHost mHost; + private RecyclerView mRecyclerView; + private TileAdapter mTileAdapter; + private View mClose; + private View mSave; + private View mReset; public QSCustomizer(Context context, AttributeSet attrs) { super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs); @@ -83,59 +63,42 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene public void setHost(QSTileHost host) { mHost = host; - mHost.addCallback(this); mPhoneStatusBar = host.getPhoneStatusBar(); - mQsPanel.setTiles(mHost.getTiles()); - mQsPanel.setHost(mHost); - mQsPanel.setSavedTiles(); } @Override protected void onFinishInflate() { super.onFinishInflate(); - mToolbar = (Toolbar) findViewById(com.android.internal.R.id.action_bar); - TypedValue value = new TypedValue(); - mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true); - mToolbar.setNavigationIcon( - getResources().getDrawable(R.drawable.ic_close_white, mContext.getTheme())); - mToolbar.setNavigationOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - hide(0, 0); - } - }); - mToolbar.setOnMenuItemClickListener(this); - mToolbar.getMenu().add(Menu.NONE, MENU_SAVE, 0, mContext.getString(R.string.save)) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0, - mContext.getString(com.android.internal.R.string.reset)); - - mQsPanel = (CustomQSPanel) findViewById(R.id.quick_settings_panel); - - mDragButtons = (ViewGroup) findViewById(R.id.drag_buttons); - setDragging(false); - - mInfoButton = (DropButton) findViewById(R.id.info_button); - mInfoButton.setOnDropListener(this); - mRemoveButton = (DropButton) findViewById(R.id.remove_button); - mRemoveButton.setOnDropListener(this); - - mFab = (FloatingActionButton) findViewById(R.id.fab); - mFab.setImageResource(R.drawable.ic_add); - mFab.setOnClickListener(this); + mClose = findViewById(R.id.close); + mSave = findViewById(R.id.save); + mReset = findViewById(R.id.reset); + mClose.setOnClickListener(this); + mSave.setOnClickListener(this); + mReset.setOnClickListener(this); + + mRecyclerView = (RecyclerView) findViewById(android.R.id.list); + mTileAdapter = new TileAdapter(getContext()); + mRecyclerView.setAdapter(mTileAdapter); + new ItemTouchHelper(mTileAdapter.getCallback()).attachToRecyclerView(mRecyclerView); + GridLayoutManager layout = new GridLayoutManager(getContext(), 3); + layout.setSpanSizeLookup(mTileAdapter.getSizeLookup()); + mRecyclerView.setLayoutManager(layout); + mRecyclerView.addItemDecoration(mTileAdapter.getItemDecoration()); + DefaultItemAnimator animator = new DefaultItemAnimator(); + animator.setMoveDuration(TileAdapter.MOVE_DURATION); + mRecyclerView.setItemAnimator(animator); } public void show(int x, int y) { isShown = true; - mQsPanel.setSavedTiles(); mPhoneStatusBar.getStatusBarWindow().addView(this); - mQsPanel.setListening(true); + setTileSpecs(); mClipper.animateCircularClip(x, y, true, this); + new TileQueryHelper(mContext, mHost).setListener(mTileAdapter); } public void hide(int x, int y) { isShown = false; - mQsPanel.setListening(false); mClipper.animateCircularClip(x, y, false, this); } @@ -149,109 +112,35 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene for (String tile : defTiles.split(",")) { tiles.add(tile); } - mQsPanel.setTiles(tiles); - } - - private void setDragging(boolean dragging) { - mToolbar.setVisibility(!dragging ? View.VISIBLE : View.INVISIBLE); - } - - private void save() { - Log.d("CustomQSPanel", "Save!"); - mQsPanel.saveCurrentTiles(); - // TODO: At save button. - hide(0, 0); - } - - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case MENU_SAVE: - Log.d("CustomQSPanel", "Save..."); - save(); - break; - case MENU_RESET: - reset(); - break; - } - return true; + mTileAdapter.setTileSpecs(tiles); } - @Override - public void onTileSelected(String spec) { - if (mDialog != null) { - mQsPanel.addTile(spec); - mDialog.dismiss(); - } - } - - @Override - public void onTilesChanged() { - mQsPanel.setTiles(mHost.getTiles()); - } - - public boolean onDragEvent(DragEvent event) { - switch (event.getAction()) { - case DragEvent.ACTION_DRAG_STARTED: - setDragging(true); - break; - case DragEvent.ACTION_DRAG_ENDED: - setDragging(false); - break; + private void setTileSpecs() { + List<String> specs = new ArrayList<>(); + for (QSTile tile : mHost.getTiles()) { + specs.add(tile.getTileSpec()); } - return true; + mTileAdapter.setTileSpecs(specs); } - public void onDrop(View v, ClipData data) { - if (v == mRemoveButton) { - mQsPanel.remove(mQsPanel.getSpec(data)); - } else if (v == mInfoButton) { - mQsPanel.unstashTiles(); - SystemUIDialog dialog = new SystemUIDialog(mContext); - dialog.setTitle(mQsPanel.getSpec(data)); - dialog.setPositiveButton(R.string.ok, null); - dialog.show(); - } + private void save() { + mTileAdapter.saveSpecs(mHost); + hide((int) mSave.getX() + mSave.getWidth() / 2, (int) mSave.getY() + mSave.getHeight() / 2); } @Override public void onClick(View v) { - if (mFab == v) { - mDialog = new SystemUIDialog(mContext, - android.R.style.Theme_Material_Dialog); - View view = LayoutInflater.from(mContext).inflate(R.layout.qs_add_tiles_list, null); - ListView listView = (ListView) view.findViewById(android.R.id.list); - TileAdapter adapter = new TileAdapter(mContext, mQsPanel.getTiles(), mHost); - adapter.setListener(this); - listView.setDivider(null); - listView.setDividerHeight(0); - listView.setAdapter(adapter); - listView.setEmptyView(view.findViewById(R.id.empty_text)); - mDialog.setView(view); - mDialog.setOnDismissListener(this); - mDialog.setOnCancelListener(this); - mDialog.show(); - // Too lazy to figure out what this will be now, but it should probably be something - // besides just a dialog. - // For now, just make it big. - WindowManager.LayoutParams params = mDialog.getWindow().getAttributes(); - params.width = WindowManager.LayoutParams.MATCH_PARENT; - params.height = WindowManager.LayoutParams.WRAP_CONTENT; - mDialog.getWindow().setAttributes(params); + if (v == mClose) { + hide((int) mClose.getX() + mClose.getWidth() / 2, + (int) mClose.getY() + mClose.getHeight() / 2); + } else if (v == mSave) { + save(); + } else if (v == mReset) { + reset(); } } @Override - public void onDismiss(DialogInterface dialog) { - mDialog = null; - } - - @Override - public void onCancel(DialogInterface dialog) { - mDialog = null; - } - - @Override public void onAnimationEnd(Animator animation) { if (!isShown) { mPhoneStatusBar.getStatusBarWindow().removeView(this); @@ -274,4 +163,4 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene public void onAnimationRepeat(Animator animation) { // Don't care. } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java index b72789ef9f3c..fb3818cf9db1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java @@ -1,262 +1,293 @@ /* - * 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. - * You may obtain a copy of the License at + * 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. + * 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.qs.customize; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.Looper; -import android.service.quicksettings.TileService; -import android.util.Log; +import android.graphics.Canvas; +import android.graphics.drawable.ColorDrawable; +import android.support.v4.view.ViewCompat; +import android.support.v7.widget.GridLayoutManager.SpanSizeLookup; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.ItemDecoration; +import android.support.v7.widget.RecyclerView.State; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.support.v7.widget.helper.ItemTouchHelper.Callback; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.GridLayout; -import android.widget.ImageView; -import android.widget.TextView; - +import android.widget.FrameLayout; import com.android.systemui.R; -import com.android.systemui.qs.QSTile; -import com.android.systemui.qs.QSTile.Icon; -import com.android.systemui.qs.external.CustomTile; +import com.android.systemui.qs.QSIconView; +import com.android.systemui.qs.QSTileView; +import com.android.systemui.qs.customize.TileAdapter.Holder; +import com.android.systemui.qs.customize.TileQueryHelper.TileInfo; +import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener; import com.android.systemui.statusbar.phone.QSTileHost; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; import java.util.List; -public class TileAdapter extends BaseAdapter { +public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener { + + private static final long DRAG_LENGTH = 100; + private static final float DRAG_SCALE = 1.2f; + public static final long MOVE_DURATION = 150; - private static final String TAG = "TileAdapter"; + private static final int TYPE_TILE = 0; + private static final int TYPE_EDIT = 1; - private final ArrayList<TileGroup> mGroups = new ArrayList<>(); private final Context mContext; - private TileSelectedListener mListener; - private ArrayList<String> mCurrentTiles; + private final List<TileInfo> mTiles = new ArrayList<>(); + private int mDividerIndex; + private List<String> mCurrentSpecs; + private List<TileInfo> mOtherTiles; + private List<TileInfo> mAllTiles; + + private Holder mCurrentDrag; - public TileAdapter(Context context, Collection<QSTile<?>> currentTiles, QSTileHost host) { + public TileAdapter(Context context) { mContext = context; - addSystemTiles(currentTiles, host); - // TODO: Live? + setHasStableIds(true); } - private void addSystemTiles(Collection<QSTile<?>> currentTiles, QSTileHost host) { - try { - ArrayList<String> tileSpecs = new ArrayList<>(); - for (QSTile<?> tile : currentTiles) { - tileSpecs.add(tile.getTileSpec()); - } - mCurrentTiles = tileSpecs; - final TileGroup group = new TileGroup("com.android.settings", mContext); - boolean hasColorMod = host.getDisplayController().isEnabled(); - String possible = mContext.getString(R.string.quick_settings_tiles_default) - + ",hotspot,inversion,saver" + (hasColorMod ? ",colors" : ""); - String[] possibleTiles = possible.split(","); - for (int i = 0; i < possibleTiles.length; i++) { - final String spec = possibleTiles[i]; - if (spec.startsWith("q")) { - // Quick tiles can't be customized. - continue; - } - if (tileSpecs.contains(spec)) { - Log.d(TAG, "Skipping " + spec); - continue; - } - Log.d(TAG, "Trying " + spec); - final QSTile<?> tile = host.createTile(spec); - if (tile == null) { - continue; - } - // Bad, bad, very bad. - tile.setListening(true); - tile.clearState(); - tile.refreshState(); - tile.setListening(false); - new Handler(host.getLooper()).post(new Runnable() { - @Override - public void run() { - group.addTile(spec, tile.getState().icon, tile.getState().label, mContext); - } - }); - } - // Error: Badness (10000). - // Serialize this work after the host's looper's queue is empty. - new Handler(host.getLooper()).post(new Runnable() { - @Override - public void run() { - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - if (group.mTiles.size() > 0) { - mGroups.add(group); - notifyDataSetChanged(); - } - new QueryTilesTask().execute(); - } - }); - } - }); - } catch (NameNotFoundException e) { - Log.e(TAG, "Couldn't load system tiles", e); + @Override + public long getItemId(int position) { + return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) : -1; + } + + public Callback getCallback() { + return mCallbacks; + } + + public ItemDecoration getItemDecoration() { + return mDecoration; + } + + public void saveSpecs(QSTileHost host) { + List<String> newSpecs = new ArrayList<>(); + for (int i = 0; mTiles.get(i) != null; i++) { + newSpecs.add(mTiles.get(i).spec); + } + host.changeTiles(mCurrentSpecs, newSpecs); + setTileSpecs(newSpecs); + } + + public void setTileSpecs(List<String> currentSpecs) { + mCurrentSpecs = currentSpecs; + recalcSpecs(); + } + + @Override + public void onTilesChanged(List<TileInfo> tiles) { + mAllTiles = tiles; + recalcSpecs(); + } + + private void recalcSpecs() { + if (mCurrentSpecs == null || mAllTiles == null) { + return; } + mOtherTiles = new ArrayList<TileInfo>(mAllTiles); + mTiles.clear(); + for (int i = 0; i < mCurrentSpecs.size(); i++) { + mTiles.add(getAndRemoveOther(mCurrentSpecs.get(i))); + } + mTiles.add(null); + mTiles.addAll(mOtherTiles); + mDividerIndex = mTiles.indexOf(null); + notifyDataSetChanged(); } - public void setListener(TileSelectedListener listener) { - mListener = listener; + private TileInfo getAndRemoveOther(String s) { + for (int i = 0; i < mOtherTiles.size(); i++) { + if (mOtherTiles.get(i).spec.equals(s)) { + return mOtherTiles.remove(i); + } + } + return null; } @Override - public int getCount() { - return mGroups.size(); + public int getItemViewType(int position) { + if (mTiles.get(position) == null) { + return TYPE_EDIT; + } + return TYPE_TILE; } @Override - public Object getItem(int position) { - return mGroups.get(position); + public Holder onCreateViewHolder(ViewGroup parent, int viewType) { + final Context context = parent.getContext(); + LayoutInflater inflater = LayoutInflater.from(context); + if (viewType == 1) { + return new Holder(inflater.inflate(R.layout.qs_customize_divider, parent, false)); + } + FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent, + false); + frame.addView(new QSTileView(context, new QSIconView(context))); + return new Holder(frame); } @Override - public long getItemId(int position) { - return position; + public int getItemCount() { + return mTiles.size(); } @Override - public View getView(int position, View convertView, ViewGroup parent) { - return mGroups.get(position).getView(mContext, convertView, parent, mListener); + public void onBindViewHolder(Holder holder, int position) { + if (holder.getItemViewType() == TYPE_EDIT) return; + + TileInfo info = mTiles.get(position); + holder.mTileView.onStateChanged(info.state); + } + + public SpanSizeLookup getSizeLookup() { + return mSizeLookup; } - private static class TileGroup { - private final ArrayList<TileInfo> mTiles = new ArrayList<>(); - private CharSequence mLabel; - private Drawable mIcon; - - public TileGroup(String pkg, Context context) throws NameNotFoundException { - PackageManager pm = context.getPackageManager(); - ApplicationInfo info = pm.getApplicationInfo(pkg, 0); - mLabel = info.loadLabel(pm); - mIcon = info.loadIcon(pm); - Log.d(TAG, "Added " + mLabel); + public class Holder extends ViewHolder { + private QSTileView mTileView; + + public Holder(View itemView) { + super(itemView); + if (itemView instanceof FrameLayout) { + mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0); + } } - private void addTile(String spec, Drawable icon, CharSequence label) { - TileInfo info = new TileInfo(); - info.label = label; - info.drawable = icon; - info.spec = spec; - mTiles.add(info); + public void startDrag() { + itemView.animate() + .setDuration(DRAG_LENGTH) + .scaleX(DRAG_SCALE) + .scaleY(DRAG_SCALE); + mTileView.findViewById(R.id.tile_label).animate() + .setDuration(DRAG_LENGTH) + .alpha(0); } - private void addTile(String spec, Icon icon, CharSequence label, Context context) { - addTile(spec, icon != null ? icon.getDrawable(context) : null, label); + public void stopDrag() { + itemView.animate() + .setDuration(DRAG_LENGTH) + .scaleX(1) + .scaleY(1); + mTileView.findViewById(R.id.tile_label).animate() + .setDuration(DRAG_LENGTH) + .alpha(1); } + } - private View getView(Context context, View convertView, ViewGroup parent, - final TileSelectedListener listener) { - if (convertView == null) { - convertView = LayoutInflater.from(context).inflate(R.layout.tile_listing, parent, - false); - } - ((TextView) convertView.findViewById(android.R.id.title)).setText(mLabel); - ((ImageView) convertView.findViewById(android.R.id.icon)).setImageDrawable(mIcon); - GridLayout grid = (GridLayout) convertView.findViewById(R.id.tile_grid); - final int N = mTiles.size(); - if (grid.getChildCount() != N) { - grid.removeAllViews(); - } - for (int i = 0; i < N; i++) { - if (grid.getChildCount() <= i) { - grid.addView(createTile(context)); + private final SpanSizeLookup mSizeLookup = new SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + return getItemViewType(position) == TYPE_EDIT ? 3 : 1; + } + }; + + private final ItemDecoration mDecoration = new ItemDecoration() { + // TODO: Move this to resource. + private final ColorDrawable mDrawable = new ColorDrawable(0xff384248); + + @Override + public void onDraw(Canvas c, RecyclerView parent, State state) { + super.onDraw(c, parent, state); + + final int childCount = parent.getChildCount(); + final int width = parent.getWidth(); + final int bottom = parent.getBottom(); + for (int i = 0; i < childCount; i++) { + final View child = parent.getChildAt(i); + final ViewHolder holder = parent.getChildViewHolder(child); + if (holder.getAdapterPosition() < mDividerIndex) { + continue; } - View view = grid.getChildAt(i); - final TileInfo tileInfo = mTiles.get(i); - ((ImageView) view.findViewById(R.id.tile_icon)).setImageDrawable(tileInfo.drawable); - ((TextView) view.findViewById(R.id.tile_label)).setText(tileInfo.label); - view.setClickable(true); - view.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - listener.onTileSelected(tileInfo.spec); - } - }); + + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child + .getLayoutParams(); + final int top = child.getTop() + params.topMargin + + Math.round(ViewCompat.getTranslationY(child)); + // Draw full width, in case there aren't tiles all the way across. + mDrawable.setBounds(0, top, width, bottom); + mDrawable.draw(c); + break; } - return convertView; } + }; + + private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() { - private View createTile(Context context) { - return LayoutInflater.from(context).inflate(R.layout.qs_add_tile_layout, null); + @Override + public boolean isLongPressDragEnabled() { + return true; } - } - private static class TileInfo { - private String spec; - private Drawable drawable; - private CharSequence label; - } + @Override + public boolean isItemViewSwipeEnabled() { + return false; + } - private class QueryTilesTask extends AsyncTask<Void, Void, Collection<TileGroup>> { @Override - protected Collection<TileGroup> doInBackground(Void... params) { - HashMap<String, TileGroup> pkgMap = new HashMap<>(); - PackageManager pm = mContext.getPackageManager(); - // TODO: Handle userness. - List<ResolveInfo> services = pm.queryIntentServices( - new Intent(TileService.ACTION_QS_TILE), 0); - for (ResolveInfo info : services) { - String packageName = info.serviceInfo.packageName; - ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name); - String spec = CustomTile.toSpec(componentName); - if (mCurrentTiles.contains(spec)) { - continue; - } - try { - TileGroup group = pkgMap.get(packageName); - if (group == null) { - group = new TileGroup(packageName, mContext); - pkgMap.put(packageName, group); - } - Drawable icon = info.serviceInfo.loadIcon(pm); - CharSequence label = info.serviceInfo.loadLabel(pm); - group.addTile(spec, icon, label != null ? label.toString() : "null"); - } catch (NameNotFoundException e) { - Log.w(TAG, "Couldn't find resolved package... " + packageName, e); - } + public void onSelectedChanged(ViewHolder viewHolder, int actionState) { + super.onSelectedChanged(viewHolder, actionState); + if (mCurrentDrag != null) { + mCurrentDrag.stopDrag(); + } + if (viewHolder != null) { + mCurrentDrag = (Holder) viewHolder; + mCurrentDrag.startDrag(); } - return pkgMap.values(); } @Override - protected void onPostExecute(Collection<TileGroup> result) { - mGroups.addAll(result); - notifyDataSetChanged(); + public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) { + if (viewHolder.getItemViewType() == TYPE_EDIT) { + return makeMovementFlags(0, 0); + } + int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT + | ItemTouchHelper.LEFT; + return makeMovementFlags(dragFlags, 0); } - } - public interface TileSelectedListener { - void onTileSelected(String spec); - } + @Override + public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) { + int from = viewHolder.getAdapterPosition(); + int to = target.getAdapterPosition(); + if (to > mDividerIndex) { + if (from < mDividerIndex) { + to = mDividerIndex; + } else { + return false; + } + } + if (target.getItemViewType() == TYPE_EDIT && from < mDividerIndex) { + to++; + } + move(from, to, mTiles); + mDividerIndex = mTiles.indexOf(null); + notifyItemMoved(from, to); + return true; + } + + private <T> void move(int from, int to, List<T> list) { + list.add(from > to ? to : to + 1, list.get(from)); + list.remove(from > to ? from + 1 : from); + } + + @Override + public void onSwiped(ViewHolder viewHolder, int direction) { + } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java new file mode 100644 index 000000000000..6840e08f2cfe --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.customize; + +import android.app.ActivityManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.Handler; +import android.os.Looper; +import android.service.quicksettings.TileService; +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.QSTile.DrawableIcon; +import com.android.systemui.qs.external.CustomTile; +import com.android.systemui.statusbar.phone.QSTileHost; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class TileQueryHelper { + + private static final String TAG = "TileQueryHelper"; + + private final ArrayList<TileInfo> mTiles = new ArrayList<>(); + private final Context mContext; + private TileStateListener mListener; + + public TileQueryHelper(Context context, QSTileHost host) { + mContext = context; + addSystemTiles(host); + // TODO: Live? + } + + private void addSystemTiles(QSTileHost host) { + boolean hasColorMod = host.getDisplayController().isEnabled(); + String possible = mContext.getString(R.string.quick_settings_tiles_default) + + ",hotspot,inversion,saver" + (hasColorMod ? ",colors" : ""); + String[] possibleTiles = possible.split(","); + final Handler qsHandler = new Handler(host.getLooper()); + final Handler mainHandler = new Handler(Looper.getMainLooper()); + for (int i = 0; i < possibleTiles.length; i++) { + final String spec = possibleTiles[i]; + final QSTile<?> tile = host.createTile(spec); + if (tile == null) { + continue; + } + tile.setListening(true); + tile.clearState(); + tile.refreshState(); + tile.setListening(false); + qsHandler.post(new Runnable() { + @Override + public void run() { + final QSTile.State state = tile.newTileState(); + tile.getState().copyTo(state); + mainHandler.post(new Runnable() { + @Override + public void run() { + addTile(spec, state, mTiles); + mListener.onTilesChanged(mTiles); + } + }); + } + }); + } + qsHandler.post(new Runnable() { + @Override + public void run() { + new QueryTilesTask().execute(); + } + }); + } + + public void setListener(TileStateListener listener) { + mListener = listener; + } + + private static void addTile(String spec, QSTile.State state, List<TileInfo> tiles) { + TileInfo info = new TileInfo(); + info.state = state; + info.spec = spec; + tiles.add(info); + } + + private static void addTile(String spec, Drawable drawable, CharSequence label, Context context, + List<TileInfo> tiles) { + QSTile.State state = new QSTile.State(); + state.label = label; + state.contentDescription = label; + state.icon = new DrawableIcon(drawable); + addTile(spec, state, tiles); + } + + public static class TileInfo { + public String spec; + public QSTile.State state; + } + + private class QueryTilesTask extends AsyncTask<Void, Void, Collection<TileInfo>> { + @Override + protected Collection<TileInfo> doInBackground(Void... params) { + List<TileInfo> tiles = new ArrayList<>(); + PackageManager pm = mContext.getPackageManager(); + List<ResolveInfo> services = pm.queryIntentServicesAsUser( + new Intent(TileService.ACTION_QS_TILE), 0, ActivityManager.getCurrentUser()); + for (ResolveInfo info : services) { + String packageName = info.serviceInfo.packageName; + ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name); + String spec = CustomTile.toSpec(componentName); + Drawable icon = info.serviceInfo.loadIcon(pm); + if (icon != null) { + icon.mutate(); + icon.setTint(mContext.getColor(android.R.color.white)); + } + CharSequence label = info.serviceInfo.loadLabel(pm); + addTile(spec, icon, label != null ? label.toString() : "null", mContext, tiles); + } + return tiles; + } + + @Override + protected void onPostExecute(Collection<TileInfo> result) { + mTiles.addAll(result); + mListener.onTilesChanged(mTiles); + } + } + + public interface TileStateListener { + void onTilesChanged(List<TileInfo> tiles); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index df3b5de9078b..3cd9e67e1269 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -151,7 +151,7 @@ public class CustomTile extends QSTile<QSTile.State> { } @Override - protected State newTileState() { + public State newTileState() { return new State(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java index d78d6ffe2cfe..5222e61ab5d3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java @@ -51,7 +51,7 @@ public class AirplaneModeTile extends QSTile<QSTile.BooleanState> { } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } 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 64b3a6c6d359..cd3e3b2a3bf0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java @@ -54,7 +54,7 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll } @Override - protected State newTileState() { + public State newTileState() { return new QSTile.State(); } 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 874fc3ec0b88..1dce053f0ff3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -56,7 +56,7 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> { } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } 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 18eb7a1ded02..15e082abff67 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -60,7 +60,7 @@ public class CastTile extends QSTile<QSTile.BooleanState> { } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } 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 aacdbc9c77d3..c3a2ebe18303 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -54,7 +54,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> { } @Override - protected SignalState newTileState() { + public SignalState newTileState() { return new SignalState(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index 6e843e911212..e98734cb3f43 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -54,7 +54,7 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> { } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java index 1aeb0fe6c9dd..c6a98b4fb1d9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java @@ -30,7 +30,7 @@ public class DataSaverTile extends QSTile<QSTile.BooleanState> implements } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } 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 f99a3e4b73e9..58872ecdb2c4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -94,7 +94,7 @@ public class DndTile extends QSTile<QSTile.BooleanState> { } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index 1d9f15bbf7a9..f06634e9cb78 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -47,7 +47,7 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index 2f37943196fa..943b502a565f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -44,7 +44,7 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java index e1dc9f2b9cc2..bdf95d8782bf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java @@ -75,7 +75,7 @@ public class IntentTile extends QSTile<QSTile.State> { } @Override - protected State newTileState() { + public State newTileState() { return new State(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java index 8328897c47b9..9f41f9a17a83 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -45,7 +45,7 @@ public class LocationTile extends QSTile<QSTile.BooleanState> { } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java index f920d4806284..c94cf5a9bec2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -46,7 +46,7 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> { } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java index 1565b6f0251e..ba7ea4d66453 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java @@ -37,7 +37,7 @@ public class UserTile extends QSTile<QSTile.State> implements UserInfoController } @Override - protected State newTileState() { + public State newTileState() { return new QSTile.State(); } 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 42296f2aad36..ac4dfd54a0d4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -60,7 +60,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> { } @Override - protected SignalState newTileState() { + public SignalState newTileState() { return new SignalState(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index 508490ffa881..a94973c43f7a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -53,7 +53,7 @@ public class WorkModeTile extends QSTile<QSTile.BooleanState> { } @Override - protected BooleanState newTileState() { + public BooleanState newTileState() { return new BooleanState(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index d01a288d6fcf..3f482c82011a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -45,7 +45,6 @@ import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEven import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent; import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent; import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted; -import com.android.systemui.recents.events.activity.EnterRecentsTaskStackAnimationCompletedEvent; import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent; import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent; import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent; @@ -130,6 +129,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD */ public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) { mLaunchIntent = launchIntent; + mOpts = opts; } @Override @@ -437,11 +437,8 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD protected void onPause() { super.onPause(); - RecentsDebugFlags flags = Recents.getDebugFlags(); - if (flags.isFastToggleRecentsEnabled()) { - // Stop the fast-toggle dozer - mIterateTrigger.stopDozing(); - } + // Stop the fast-toggle dozer + mIterateTrigger.stopDozing(); } @Override @@ -648,6 +645,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD } public final void onBusEvent(UserInteractionEvent event) { + // Stop the fast-toggle dozer mIterateTrigger.stopDozing(); } @@ -694,21 +692,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD } } - public final void onBusEvent(EnterRecentsTaskStackAnimationCompletedEvent event) { - RecentsDebugFlags debugFlags = Recents.getDebugFlags(); - RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); - if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled() && - RecentsDebugFlags.Static.EnableFastToggleTimeoutOnEnter) { - mIterateTrigger.setDozeDuration( - getResources().getInteger(R.integer.recents_auto_advance_duration)); - if (!mIterateTrigger.isDozing()) { - mIterateTrigger.startDozing(); - } else { - mIterateTrigger.poke(); - } - } - } - public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) { EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true)); mRecentsView.getViewTreeObserver().addOnPreDrawListener(this); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java index 0afa1f6a495f..177e8417f3fb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java @@ -52,10 +52,23 @@ public class RecentsActivityLaunchState { * Returns the task to focus given the current launch state. */ public int getInitialFocusTaskIndex(int numTasks) { + RecentsDebugFlags debugFlags = Recents.getDebugFlags(); if (launchedFromAppWithThumbnail) { + if (debugFlags.isFastToggleRecentsEnabled()) { + // If fast toggling, focus the front most task so that the next tap will focus the + // N-1 task + return numTasks - 1; + } + // If coming from another app, focus the next task return numTasks - 2; } else { + if (debugFlags.isFastToggleRecentsEnabled()) { + // If fast toggling, defer focusing until the next tap (which will automatically + // focus the front most task) + return -1; + } + // If coming from home, focus the first task return numTasks - 1; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java index 6b8968f02a11..fc14758af0f4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java @@ -39,8 +39,6 @@ public class RecentsDebugFlags implements TunerService.Tunable { public static final boolean EnableAffiliatedTaskGroups = true; // Overrides the Tuner flags and enables the fast toggle and timeout public static final boolean EnableFastToggleTimeoutOverride = true; - // Enables toggling the fast-toggle timeout immediately after entering Recents - public static final boolean EnableFastToggleTimeoutOnEnter = true; // Enables us to create mock recents tasks public static final boolean EnableMockTasks = false; @@ -90,9 +88,6 @@ public class RecentsDebugFlags implements TunerService.Tunable { * @return whether the initial stack state is paging. */ public boolean isInitialStatePaging() { - if (Static.EnableFastToggleTimeoutOnEnter) { - return true; - } return mInitialStatePaging; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 1cceef4484fe..dd7b7c1b89e6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -38,6 +38,7 @@ import android.util.MutableBoolean; import android.view.AppTransitionAnimationSpec; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewConfiguration; import com.android.internal.logging.MetricsLogger; import com.android.systemui.Prefs; @@ -48,6 +49,7 @@ import com.android.systemui.recents.events.activity.DockingTopTaskEvent; import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent; import com.android.systemui.recents.events.activity.HideRecentsEvent; import com.android.systemui.recents.events.activity.IterateRecentsEvent; +import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent; import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; import com.android.systemui.recents.events.activity.ToggleRecentsEvent; import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; @@ -81,8 +83,10 @@ import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener { private final static String TAG = "RecentsImpl"; + // 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) // that the fast alt-tab animation will run. If the user's alt-tab takes longer than this // duration, then we will toggle recents after this duration. @@ -337,21 +341,31 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener mTriggeredFromAltTab = false; try { + ViewConfiguration viewConfig = ViewConfiguration.get(mContext); SystemServicesProxy ssp = Recents.getSystemServices(); ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); MutableBoolean isTopTaskHome = new MutableBoolean(true); + long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime; + if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) { RecentsConfiguration config = Recents.getConfiguration(); RecentsActivityLaunchState launchState = config.getLaunchState(); if (!launchState.launchedWithAltTab) { - // Notify recents to move onto the next task - EventBus.getDefault().post(new IterateRecentsEvent()); + // If the user taps quickly + if (ViewConfiguration.getDoubleTapMinTime() < elapsedTime && + elapsedTime < ViewConfiguration.getDoubleTapTimeout()) { + // Launch the next focused task + EventBus.getDefault().post(new LaunchNextTaskRequestEvent()); + } else { + // Notify recents to move onto the next task + EventBus.getDefault().post(new IterateRecentsEvent()); + } } else { // If the user has toggled it too quickly, then just eat up the event here (it's // better than showing a janky screenshot). // NOTE: Ideally, the screenshot mechanism would take the window transform into // account - if ((SystemClock.elapsedRealtime() - mLastToggleTime) < MIN_TOGGLE_DELAY_MS) { + if (elapsedTime < MIN_TOGGLE_DELAY_MS) { return; } @@ -364,7 +378,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // better than showing a janky screenshot). // NOTE: Ideally, the screenshot mechanism would take the window transform into // account - if ((SystemClock.elapsedRealtime() - mLastToggleTime) < MIN_TOGGLE_DELAY_MS) { + if (elapsedTime < MIN_TOGGLE_DELAY_MS) { return; } @@ -551,11 +565,14 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener public void dockTopTask(int topTaskId, int dragMode, int stackCreateMode, Rect initialBounds) { SystemServicesProxy ssp = Recents.getSystemServices(); + + // Make sure we inform DividerView before we actually start the activity so we can change + // the resize mode already. + EventBus.getDefault().send(new DockingTopTaskEvent(dragMode)); ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds); showRecents(false /* triggeredFromAltTab */, dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, false /* animate */, true /* reloadTasks*/); - EventBus.getDefault().send(new DockingTopTaskEvent(dragMode)); } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java new file mode 100644 index 000000000000..11604b51b4a5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents.events.activity; + +import com.android.systemui.recents.events.EventBus; + +/** + * This event is sent to request that the next task is launched after a double-tap on the Recents + * button. + */ +public class LaunchNextTaskRequestEvent extends EventBus.Event { + // Simple event +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java new file mode 100644 index 000000000000..d5083a8b017f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.recents.events.activity; + +import com.android.systemui.recents.events.EventBus; + +/** + * Fires when the user invoked the gesture to undock the task in the docked stack. + */ +public class UndockingTaskEvent extends EventBus.Event { + + public UndockingTaskEvent() { + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java index ee3eb02c8a38..5eeda72637ea 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java @@ -67,9 +67,30 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd public static class ViewHolder extends RecyclerView.ViewHolder implements Task.TaskCallbacks { public final View content; - public ViewHolder(View v) { - super(v); - content = v; + private Task mTask; + + public ViewHolder(View content) { + super(content); + this.content = content; + } + + /** + * Binds this view holder to the given task. + */ + public void bindToTask(Task newTask) { + unbindFromTask(); + mTask = newTask; + mTask.addCallback(this); + } + + /** + * Unbinds this view holder from the + */ + public void unbindFromTask() { + if (mTask != null) { + mTask.removeCallback(this); + mTask = null; + } } @Override @@ -267,12 +288,13 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd } case TASK_ROW_VIEW_TYPE: { TaskRow taskRow = (TaskRow) row; - taskRow.task.addCallback(holder); TextView tv = (TextView) holder.content.findViewById(R.id.description); tv.setText(taskRow.task.title); ImageView iv = (ImageView) holder.content.findViewById(R.id.icon); iv.setAlpha(0f); holder.content.setOnClickListener(taskRow); + + holder.bindToTask(taskRow.task); loader.loadTaskData(taskRow.task, false /* fetchAndInvalidateThumbnails */); break; } @@ -289,7 +311,7 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd if (viewType == TASK_ROW_VIEW_TYPE) { TaskRow taskRow = (TaskRow) row; loader.unloadTaskData(taskRow.task); - taskRow.task.removeCallback(holder); + holder.unbindFromTask(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java index e8fa39830f8d..1cd0850ef7fa 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java @@ -83,13 +83,11 @@ public class SystemBarScrimViews { * going home). */ public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) { - int taskViewExitToAppDuration = mContext.getResources().getInteger( - R.integer.recents_task_exit_to_app_duration); if (mHasNavBarScrim && mShouldAnimateNavBarScrim) { mNavBarScrimView.animate() .translationY(mNavBarScrimView.getMeasuredHeight()) .setStartDelay(0) - .setDuration(taskViewExitToAppDuration) + .setDuration(TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .start(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java index 0eae183e58d6..7eaa1930f6a6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java @@ -108,7 +108,7 @@ public class TaskStackAnimationHelper { return; } - int offscreenY = stackLayout.mStackRect.bottom; + int offscreenYOffset = stackLayout.mStackRect.height(); int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize( R.dimen.recents_task_view_affiliate_group_enter_offset); @@ -145,7 +145,7 @@ public class TaskStackAnimationHelper { } else if (launchState.launchedFromHome) { // Move the task view off screen (below) so we can animate it in RectF bounds = new RectF(mTmpTransform.rect); - bounds.offsetTo(bounds.left, offscreenY); + bounds.offset(0, offscreenYOffset); tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom); } @@ -247,7 +247,7 @@ public class TaskStackAnimationHelper { return; } - int offscreenY = stackLayout.mStackRect.bottom; + int offscreenYOffset = stackLayout.mStackRect.height(); // Create the animations for each of the tasks List<TaskView> taskViews = mStackView.getTaskViews(); @@ -277,7 +277,7 @@ public class TaskStackAnimationHelper { stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, null); - mTmpTransform.rect.offsetTo(mTmpTransform.rect.left, offscreenY); + mTmpTransform.rect.offset(0, offscreenYOffset); mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); } } 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 46fdb2a9b860..bd37c3bfd761 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -383,6 +383,7 @@ public class TaskStackLayoutAlgorithm { */ void update(TaskStack stack, ArraySet<Task.TaskKey> ignoreTasksSet) { SystemServicesProxy ssp = Recents.getSystemServices(); + RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); // Clear the progress map mTaskIndexMap.clear(); @@ -449,7 +450,6 @@ public class TaskStackLayoutAlgorithm { if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) { mInitialScrollP = mMinScrollP; } else if (getDefaultFocusState() > 0f) { - RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); if (launchState.launchedFromHome) { mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, launchTaskIndex)); } else { @@ -568,7 +568,7 @@ public class TaskStackLayoutAlgorithm { boolean isFrontMostTaskInGroup = task.group == null || task.group.isFrontMostTask(task); if (isFrontMostTaskInGroup) { getStackTransform(taskProgress, mInitialScrollP, tmpTransform, null, - false /* ignoreSingleTaskCase */); + false /* ignoreSingleTaskCase */, false /* forceUpdate */); float screenY = tmpTransform.rect.top; boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight; if (hasVisibleThumbnail) { @@ -601,6 +601,12 @@ public class TaskStackLayoutAlgorithm { */ public TaskViewTransform getStackTransform(Task task, float stackScroll, TaskViewTransform transformOut, TaskViewTransform frontTransform) { + return getStackTransform(task, stackScroll, transformOut, frontTransform, + false /* forceUpdate */); + } + + public TaskViewTransform getStackTransform(Task task, float stackScroll, + TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate) { if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) { mFreeformLayoutAlgorithm.getTransform(task, transformOut, this); return transformOut; @@ -610,8 +616,9 @@ public class TaskStackLayoutAlgorithm { transformOut.reset(); return transformOut; } - return getStackTransform(mTaskIndexMap.get(task.key), stackScroll, transformOut, - frontTransform, false /* ignoreSingleTaskCase */); + getStackTransform(mTaskIndexMap.get(task.key), stackScroll, transformOut, + frontTransform, false /* ignoreSingleTaskCase */, forceUpdate); + return transformOut; } } @@ -635,9 +642,9 @@ public class TaskStackLayoutAlgorithm { * internally to ensure that we can calculate the transform for any * position in the stack. */ - public TaskViewTransform getStackTransform(float taskProgress, float stackScroll, + public void getStackTransform(float taskProgress, float stackScroll, TaskViewTransform transformOut, TaskViewTransform frontTransform, - boolean ignoreSingleTaskCase) { + boolean ignoreSingleTaskCase, boolean forceUpdate) { SystemServicesProxy ssp = Recents.getSystemServices(); // Compute the focused and unfocused offset @@ -658,9 +665,9 @@ public class TaskStackLayoutAlgorithm { } // Skip if the task is not visible - if (!unfocusedVisible && !focusedVisible) { + if (!forceUpdate && !unfocusedVisible && !focusedVisible) { transformOut.reset(); - return transformOut; + return; } int x = (mStackRect.width() - mTaskRect.width()) / 2; @@ -700,7 +707,6 @@ public class TaskStackLayoutAlgorithm { transformOut.visible = (transformOut.rect.top < mStackRect.bottom) && (frontTransform == null || transformOut.rect.top != frontTransform.rect.top); transformOut.p = relP; - return transformOut; } /** @@ -797,8 +803,10 @@ public class TaskStackLayoutAlgorithm { mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin); float max = mUnfocusedRange.relativeMax + mFocusState * (mFocusedRange.relativeMax - mUnfocusedRange.relativeMax); - getStackTransform(min, 0f, mBackOfStackTransform, null, true /* ignoreSingleTaskCase */); - getStackTransform(max, 0f, mFrontOfStackTransform, null, true /* ignoreSingleTaskCase */); + getStackTransform(min, 0f, mBackOfStackTransform, null, true /* ignoreSingleTaskCase */, + true /* forceUpdate */); + getStackTransform(max, 0f, mFrontOfStackTransform, null, true /* ignoreSingleTaskCase */, + true /* forceUpdate */); mBackOfStackTransform.visible = true; mFrontOfStackTransform.visible = true; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 1c97b5a22ec7..bb74de493f58 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -58,6 +58,7 @@ import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationC import com.android.systemui.recents.events.activity.HideHistoryButtonEvent; import com.android.systemui.recents.events.activity.HideHistoryEvent; import com.android.systemui.recents.events.activity.IterateRecentsEvent; +import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent; import com.android.systemui.recents.events.activity.LaunchTaskEvent; import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent; import com.android.systemui.recents.events.activity.PackagesChangedEvent; @@ -654,7 +655,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal transform.fillIn(tv); } else { mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(), - transform, null); + transform, null, true /* forceUpdate */); } transform.visible = true; } @@ -1544,6 +1545,24 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mUIDozeTrigger.stopDozing(); } + public final void onBusEvent(LaunchNextTaskRequestEvent event) { + int launchTaskIndex = mStack.indexOfStackTask(mStack.getLaunchTarget()); + if (launchTaskIndex != -1) { + launchTaskIndex = Math.max(0, launchTaskIndex - 1); + } else { + launchTaskIndex = mStack.getTaskCount() - 1; + } + if (launchTaskIndex != -1) { + // Stop all animations + mUIDozeTrigger.stopDozing(); + cancelAllTaskViewAnimations(); + + Task launchTask = mStack.getStackTasks().get(launchTaskIndex); + EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(launchTask), + launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */)); + } + } + public final void onBusEvent(LaunchTaskStartedEvent event) { mAnimationHelper.startLaunchTaskAnimation(event.taskView, event.screenPinningRequested, event.getAnimationTrigger()); @@ -1762,21 +1781,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } - public final void onBusEvent(EnterRecentsTaskStackAnimationCompletedEvent event) { - RecentsDebugFlags debugFlags = Recents.getDebugFlags(); - RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); - if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled() && - RecentsDebugFlags.Static.EnableFastToggleTimeoutOnEnter) { - if (mFocusedTask != null) { - int timerIndicatorDuration = getResources().getInteger( - R.integer.recents_auto_advance_duration); - int focusedTaskIndex = mStack.indexOfStackTask(mFocusedTask); - setFocusedTask(focusedTaskIndex, false /* scrollToTask */, - false /* requestViewFocus */, timerIndicatorDuration); - } - } - } - public final void onBusEvent(UpdateFreeformTaskViewVisibilityEvent event) { List<TaskView> taskViews = getTaskViews(); int taskViewCount = taskViews.size(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index b8b506800488..d6680fdf23e2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -29,6 +29,7 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewParent; +import android.view.animation.Animation; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; @@ -497,6 +498,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { // onBeginDrag(). mSv.removeIgnoreTask(tv.getTask()); mSv.updateLayoutAlgorithm(false /* boundScroll */); + mSv.relayoutTaskViews(AnimationProps.IMMEDIATE); mSwipeHelperAnimations.remove(v); } 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 703005f00a49..439d96f7d27b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -242,7 +242,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks } void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, - AnimationProps toAnimation, ValueAnimator.AnimatorUpdateListener updateCallback) { + AnimationProps toAnimation, ValueAnimator.AnimatorUpdateListener updateCallback) { RecentsConfiguration config = Recents.getConfiguration(); cancelTransformAnimation(); @@ -261,14 +261,16 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks updateCallback.onAnimationUpdate(null); } } else { + // Both the progress and the update are a function of the bounds movement of the task if (Float.compare(getTaskProgress(), toTransform.p) != 0) { - mTmpAnimators.add(ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(), - toTransform.p)); + ObjectAnimator anim = ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(), + toTransform.p); + mTmpAnimators.add(toAnimation.apply(AnimationProps.BOUNDS, anim)); } if (updateCallback != null) { ValueAnimator updateCallbackAnim = ValueAnimator.ofInt(0, 1); updateCallbackAnim.addUpdateListener(updateCallback); - mTmpAnimators.add(updateCallbackAnim); + mTmpAnimators.add(toAnimation.apply(AnimationProps.BOUNDS, updateCallbackAnim)); } // Create the animator diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java index 5ef56f3312dd..12e271397fba 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java @@ -26,10 +26,9 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Property; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; import android.widget.ImageButton; +import com.android.systemui.Interpolators; import com.android.systemui.R; /** @@ -71,7 +70,6 @@ public class DividerHandleView extends ImageButton { private final int mWidth; private final int mHeight; private final int mCircleDiameter; - private final Interpolator mFastOutSlowInInterpolator; private int mCurrentWidth; private int mCurrentHeight; private AnimatorSet mAnimator; @@ -85,8 +83,6 @@ public class DividerHandleView extends ImageButton { mCurrentWidth = mWidth; mCurrentHeight = mHeight; mCircleDiameter = (mWidth + mHeight) / 3; - mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(), - android.R.interpolator.fast_out_slow_in); } public void setTouching(boolean touching, boolean animate) { @@ -120,8 +116,8 @@ public class DividerHandleView extends ImageButton { ? DividerView.TOUCH_ANIMATION_DURATION : DividerView.TOUCH_RELEASE_ANIMATION_DURATION); mAnimator.setInterpolator(touching - ? DividerView.TOUCH_RESPONSE_INTERPOLATOR - : mFastOutSlowInInterpolator); + ? Interpolators.TOUCH_RESPONSE + : Interpolators.FAST_OUT_SLOW_IN); mAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 1e11fa81f3bc..83c22b110433 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -48,10 +48,12 @@ import android.widget.FrameLayout; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.internal.policy.DockedDividerUtils; +import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.DockingTopTaskEvent; import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; +import com.android.systemui.recents.events.activity.UndockingTaskEvent; import com.android.systemui.recents.events.ui.RecentsDrawnEvent; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.phone.NavigationBarGestureHelper; @@ -67,8 +69,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, static final long TOUCH_ANIMATION_DURATION = 150; static final long TOUCH_RELEASE_ANIMATION_DURATION = 200; - static final Interpolator TOUCH_RESPONSE_INTERPOLATOR = - new PathInterpolator(0.3f, 0f, 0.1f, 1f); private static final String TAG = "DividerView"; @@ -116,7 +116,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, private final Rect mOtherInsetRect = new Rect(); private final Rect mLastResizeRect = new Rect(); private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance(); - private Interpolator mFastOutSlowInInterpolator; private DividerWindowManager mWindowManager; private VelocityTracker mVelocityTracker; private FlingAnimationUtils mFlingAnimationUtils; @@ -158,8 +157,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, mTouchElevation = getResources().getDimensionPixelSize( R.dimen.docked_stack_divider_lift_elevation); mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow); - mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(), - android.R.interpolator.fast_out_slow_in); mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f); updateDisplayInfo(); @@ -192,7 +189,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, insets.getStableInsetRight(), insets.getStableInsetBottom()); if (mSnapAlgorithm != null) { mSnapAlgorithm = null; - getSnapAlgorithm(); + initializeSnapAlgorithm(); } } return super.onApplyWindowInsets(insets); @@ -211,17 +208,13 @@ public class DividerView extends FrameLayout implements OnTouchListener, mHandle.setTouching(true, animate); } mDockSide = mWindowManagerProxy.getDockSide(); - getSnapAlgorithm(); - if (mDockSide != WindowManager.DOCKED_INVALID) { - mWindowManagerProxy.setResizing(true); - mWindowManager.setSlippery(false); - if (touching) { - liftBackground(); - } - return true; - } else { - return false; + initializeSnapAlgorithm(); + mWindowManagerProxy.setResizing(true); + mWindowManager.setSlippery(false); + if (touching) { + liftBackground(); } + return mDockSide != WindowManager.DOCKED_INVALID; } public void stopDragging(int position, float velocity, boolean avoidDismissStart) { @@ -233,17 +226,36 @@ public class DividerView extends FrameLayout implements OnTouchListener, public void stopDragging(int position, SnapTarget target, long duration, Interpolator interpolator) { + stopDragging(position, target, duration, 0 /* startDelay*/, interpolator); + } + + public void stopDragging(int position, SnapTarget target, long duration, long startDelay, + Interpolator interpolator) { mHandle.setTouching(false, true /* animate */); - flingTo(position, target, duration, interpolator); + flingTo(position, target, duration, startDelay, interpolator); mWindowManager.setSlippery(true); releaseBackground(); } - public DividerSnapAlgorithm getSnapAlgorithm() { + private void stopDragging() { + mHandle.setTouching(false, true /* animate */); + mWindowManager.setSlippery(true); + releaseBackground(); + } + + private void updateDockSide() { + mDockSide = mWindowManagerProxy.getDockSide(); + } + + private void initializeSnapAlgorithm() { if (mSnapAlgorithm == null) { mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets); } + } + + public DividerSnapAlgorithm getSnapAlgorithm() { + initializeSnapAlgorithm(); return mSnapAlgorithm; } @@ -267,6 +279,11 @@ public class DividerView extends FrameLayout implements OnTouchListener, mStartX = (int) event.getX(); mStartY = (int) event.getY(); boolean result = startDragging(true /* animate */, true /* touching */); + if (!result) { + + // Weren't able to start dragging successfully, so cancel it again. + stopDragging(); + } mStartPosition = getCurrentPosition(); mMoving = false; return result; @@ -320,10 +337,11 @@ public class DividerView extends FrameLayout implements OnTouchListener, anim.start(); } - private void flingTo(int position, SnapTarget target, long duration, + private void flingTo(int position, SnapTarget target, long duration, long startDelay, Interpolator interpolator) { ValueAnimator anim = getFlingAnimator(position, target); anim.setDuration(duration); + anim.setStartDelay(startDelay); anim.setInterpolator(interpolator); anim.start(); } @@ -377,7 +395,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mBackground.animate().scaleX(1.4f); } mBackground.animate() - .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR) + .setInterpolator(Interpolators.TOUCH_RESPONSE) .setDuration(TOUCH_ANIMATION_DURATION) .translationZ(mTouchElevation) .start(); @@ -385,7 +403,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, // Lift handle as well so it doesn't get behind the background, even though it doesn't // cast shadow. mHandle.animate() - .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR) + .setInterpolator(Interpolators.TOUCH_RESPONSE) .setDuration(TOUCH_ANIMATION_DURATION) .translationZ(mTouchElevation) .start(); @@ -393,14 +411,14 @@ public class DividerView extends FrameLayout implements OnTouchListener, private void releaseBackground() { mBackground.animate() - .setInterpolator(mFastOutSlowInInterpolator) + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .setDuration(TOUCH_RELEASE_ANIMATION_DURATION) .translationZ(0) .scaleX(1f) .scaleY(1f) .start(); mHandle.animate() - .setInterpolator(mFastOutSlowInInterpolator) + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .setDuration(TOUCH_RELEASE_ANIMATION_DURATION) .translationZ(0) .start(); @@ -421,6 +439,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mDisplayWidth = info.logicalWidth; mDisplayHeight = info.logicalHeight; mSnapAlgorithm = null; + initializeSnapAlgorithm(); } private int calculatePosition(int touchX, int touchY) { @@ -725,13 +744,29 @@ public class DividerView extends FrameLayout implements OnTouchListener, public final void onBusEvent(RecentsDrawnEvent drawnEvent) { if (mAnimateAfterRecentsDrawn) { mAnimateAfterRecentsDrawn = false; + updateDockSide(); stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250, - TOUCH_RESPONSE_INTERPOLATOR); + Interpolators.TOUCH_RESPONSE); } if (mGrowAfterRecentsDrawn) { mGrowAfterRecentsDrawn = false; + updateDockSide(); stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250, - TOUCH_RESPONSE_INTERPOLATOR); + Interpolators.TOUCH_RESPONSE); + } + } + + public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) { + int dockSide = mWindowManagerProxy.getDockSide(); + if (dockSide != WindowManager.DOCKED_INVALID) { + startDragging(false /* animate */, false /* touching */); + SnapTarget target = dockSideTopLeft(dockSide) + ? mSnapAlgorithm.getDismissEndTarget() + : mSnapAlgorithm.getDismissStartTarget(); + + // Don't start immediately - give a little bit time to settle the drag resize change. + stopDragging(getCurrentPosition(), target, 336 /* duration */, 100 /* startDelay */, + Interpolators.TOUCH_RESPONSE); } } } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java index 24ab5063d94e..15bcaf834f72 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java @@ -97,7 +97,7 @@ public class WindowManagerProxy { @Override public void run() { try { - ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true, false, + ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true, true, false); } catch (RemoteException e) { Log.w(TAG, "Failed to resize stack: " + e); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java index d9276bf8592b..306771491714 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java @@ -17,14 +17,12 @@ package com.android.systemui.statusbar; import android.content.Context; -import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import com.android.systemui.R; public class DismissView extends StackScrollerDecorView { - private boolean mDismissAllInProgress; private DismissViewButton mDismissButton; public DismissView(Context context, AttributeSet attrs) { @@ -53,27 +51,7 @@ public class DismissView extends StackScrollerDecorView { || touchY > mContent.getY() + mContent.getHeight(); } - public void showClearButton() { - mDismissButton.showButton(); - } - - public void setDismissAllInProgress(boolean dismissAllInProgress) { - if (dismissAllInProgress) { - setClipBounds(null); - } - mDismissAllInProgress = dismissAllInProgress; - } - - @Override - public void setClipBounds(Rect clipBounds) { - if (mDismissAllInProgress) { - // we don't want any clipping to happen! - return; - } - super.setClipBounds(clipBounds); - } - public boolean isButtonVisible() { - return mDismissButton.isButtonStatic(); + return mDismissButton.getAlpha() != 0.0f; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java index 46060f1f243b..b608d67e8eef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java @@ -17,22 +17,13 @@ package com.android.systemui.statusbar; import android.content.Context; -import android.graphics.Canvas; import android.graphics.Rect; -import android.graphics.drawable.AnimatedVectorDrawable; -import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.view.View; import android.view.ViewGroup; -import android.widget.Button; -import com.android.systemui.R; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; -public class DismissViewButton extends Button { - private AnimatedVectorDrawable mAnimatedDismissDrawable; - private final Drawable mStaticDismissDrawable; - private Drawable mActiveDrawable; +public class DismissViewButton extends AlphaOptimizedButton { public DismissViewButton(Context context) { this(context, null); @@ -49,55 +40,6 @@ public class DismissViewButton extends Button { public DismissViewButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mAnimatedDismissDrawable = (AnimatedVectorDrawable) getContext().getDrawable( - R.drawable.dismiss_all_shape_animation).mutate(); - mAnimatedDismissDrawable.setCallback(this); - mAnimatedDismissDrawable.setBounds(0, - 0, - mAnimatedDismissDrawable.getIntrinsicWidth(), - mAnimatedDismissDrawable.getIntrinsicHeight()); - mStaticDismissDrawable = getContext().getDrawable(R.drawable.dismiss_all_shape); - mStaticDismissDrawable.setBounds(0, - 0, - mStaticDismissDrawable.getIntrinsicWidth(), - mStaticDismissDrawable.getIntrinsicHeight()); - mStaticDismissDrawable.setCallback(this); - mActiveDrawable = mStaticDismissDrawable; - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - canvas.save(); - int drawableHeight = mActiveDrawable.getBounds().height(); - boolean isRtl = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL); - int dx = isRtl ? getWidth() / 2 + drawableHeight / 2 : getWidth() / 2 - drawableHeight / 2; - canvas.translate(dx, getHeight() / 2.0f + drawableHeight / - 2.0f); - canvas.scale(isRtl ? -1.0f : 1.0f, -1.0f); - mActiveDrawable.draw(canvas); - canvas.restore(); - } - - @Override - public boolean performClick() { - if (!mAnimatedDismissDrawable.isRunning()) { - mActiveDrawable = mAnimatedDismissDrawable; - mAnimatedDismissDrawable.start(); - } - return super.performClick(); - } - - @Override - protected boolean verifyDrawable(Drawable who) { - return super.verifyDrawable(who) - || who == mAnimatedDismissDrawable - || who == mStaticDismissDrawable; - } - - @Override - public boolean hasOverlappingRendering() { - return false; } /** @@ -118,16 +60,4 @@ public class DismissViewButton extends Button { outRect.top += translationY; outRect.bottom += translationY; } - - public void showButton() { - mActiveDrawable = mStaticDismissDrawable; - invalidate(); - } - - /** - * @return Whether the button is currently static and not being animated. - */ - public boolean isButtonStatic() { - return mActiveDrawable == mStaticDismissDrawable; - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java index 963920c3b91e..0b7bfa8871ee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -23,17 +23,15 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.Handler; import android.os.Looper; -import android.util.DisplayMetrics; +import android.view.ContextThemeWrapper; import android.view.KeyEvent; import android.view.KeyboardShortcutGroup; import android.view.KeyboardShortcutInfo; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager.KeyboardShortcutsReceiver; import android.widget.LinearLayout; -import android.widget.ScrollView; import android.widget.TextView; import com.android.systemui.R; @@ -65,7 +63,7 @@ public class KeyboardShortcuts { private Dialog mKeyboardShortcutsDialog; public KeyboardShortcuts(Context context) { - this.mContext = context; + this.mContext = new ContextThemeWrapper(context, android.R.style.Theme_Material_Light); } public void toggleKeyboardShortcuts() { @@ -108,40 +106,28 @@ public class KeyboardShortcuts { mHandler.post(new Runnable() { @Override public void run() { - // TODO: break all this code out into a handleShowKeyboard... - // Might add more things posted; should consider adding a custom handler so - // you can send the keyboardShortcutsGroups as part of the message. - AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext); - LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( - LAYOUT_INFLATER_SERVICE); - final View keyboardShortcutsView = inflater.inflate( - R.layout.keyboard_shortcuts_view, null); - DisplayMetrics dm = mContext.getResources().getDisplayMetrics(); - ScrollView scrollView = (ScrollView) keyboardShortcutsView.findViewById( - R.id.keyboard_shortcuts_scroll_view); - // TODO: find a better way to set the height. - scrollView.setLayoutParams(new LinearLayout.LayoutParams( - LayoutParams.WRAP_CONTENT, - (int) (dm.heightPixels * dm.density))); - - populateKeyboardShortcuts((LinearLayout) keyboardShortcutsView.findViewById( - R.id.keyboard_shortcuts_container), keyboardShortcutGroups); - dialogBuilder.setView(keyboardShortcutsView); - dialogBuilder.setPositiveButton(R.string.quick_settings_done, dialogCloseListener); - mKeyboardShortcutsDialog = dialogBuilder.create(); - mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true); - - // Setup window. - Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow(); - keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG); - keyboardShortcutsWindow.setBackgroundDrawable( - mContext.getDrawable(R.color.ksh_dialog_background_color)); - keyboardShortcutsWindow.setGravity(TOP); - mKeyboardShortcutsDialog.show(); + handleShowKeyboardShortcuts(keyboardShortcutGroups); } }); } + private void handleShowKeyboardShortcuts(List<KeyboardShortcutGroup> keyboardShortcutGroups) { + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext); + LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( + LAYOUT_INFLATER_SERVICE); + final View keyboardShortcutsView = inflater.inflate( + R.layout.keyboard_shortcuts_view, null); + populateKeyboardShortcuts((LinearLayout) keyboardShortcutsView.findViewById( + R.id.keyboard_shortcuts_container), keyboardShortcutGroups); + dialogBuilder.setView(keyboardShortcutsView); + dialogBuilder.setPositiveButton(R.string.quick_settings_done, dialogCloseListener); + mKeyboardShortcutsDialog = dialogBuilder.create(); + mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true); + Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow(); + keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG); + mKeyboardShortcutsDialog.show(); + } + private void populateKeyboardShortcuts(LinearLayout keyboardShortcutsLayout, List<KeyboardShortcutGroup> keyboardShortcutGroups) { LayoutInflater inflater = LayoutInflater.from(mContext); @@ -156,36 +142,37 @@ public class KeyboardShortcuts { : mContext.getColor(R.color.ksh_application_group_color)); keyboardShortcutsLayout.addView(categoryTitle); - LinearLayout shortcutWrapper = (LinearLayout) inflater.inflate( - R.layout.keyboard_shortcuts_wrapper, null); + LinearLayout shortcutContainer = (LinearLayout) inflater.inflate( + R.layout.keyboard_shortcuts_container, keyboardShortcutsLayout, false); final int itemsSize = group.getItems().size(); for (int j = 0; j < itemsSize; j++) { KeyboardShortcutInfo info = group.getItems().get(j); - View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item, null); + View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item, + shortcutContainer, false); TextView textView = (TextView) shortcutView .findViewById(R.id.keyboard_shortcuts_keyword); textView.setText(info.getLabel()); + LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView + .findViewById(R.id.keyboard_shortcuts_item_container); List<String> shortcutKeys = getHumanReadableShortcutKeys(info); final int shortcutKeysSize = shortcutKeys.size(); for (int k = 0; k < shortcutKeysSize; k++) { String shortcutKey = shortcutKeys.get(k); TextView shortcutKeyView = (TextView) inflater.inflate( - R.layout.keyboard_shortcuts_key_view, null); + R.layout.keyboard_shortcuts_key_view, shortcutItemsContainer, false); shortcutKeyView.setText(shortcutKey); - LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView - .findViewById(R.id.keyboard_shortcuts_item_container); shortcutItemsContainer.addView(shortcutKeyView); } - shortcutWrapper.addView(shortcutView); + shortcutContainer.addView(shortcutView); + } + keyboardShortcutsLayout.addView(shortcutContainer); + if (i < keyboardShortcutGroupsSize - 1) { + View separator = inflater.inflate( + R.layout.keyboard_shortcuts_category_separator, keyboardShortcutsLayout, + false); + keyboardShortcutsLayout.addView(separator); } - - // TODO: merge container and wrapper into one xml file - wrapper is always a child of - // container. - LinearLayout shortcutsContainer = (LinearLayout) inflater.inflate( - R.layout.keyboard_shortcuts_container, null); - shortcutsContainer.addView(shortcutWrapper); - keyboardShortcutsLayout.addView(shortcutsContainer); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java index 98a37f9bbb6d..c70aad2d4198 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java @@ -74,8 +74,7 @@ public class NotificationHeaderUtil { } private void applyToChild(View view, boolean shouldApply, int originalColor) { - if (view.getVisibility() == View.VISIBLE - && originalColor != NotificationHeaderView.NO_COLOR) { + if (originalColor != NotificationHeaderView.NO_COLOR) { ImageView imageView = (ImageView) view; imageView.getDrawable().mutate(); if (shouldApply) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java index ec7393568395..81144d553685 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java @@ -107,12 +107,13 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout public void bind(CharSequence title, CharSequence text) { mTitleView.setText(title); - if (TextUtils.isEmpty(title)) { - mTitleView.setVisibility(GONE); - } - mTextView.setText(text); + mTitleView.setVisibility(TextUtils.isEmpty(title) ? GONE : VISIBLE); if (TextUtils.isEmpty(text)) { mTextView.setVisibility(GONE); + mTextView.setText(null); + } else { + mTextView.setVisibility(VISIBLE); + mTextView.setText(text.toString()); } requestLayout(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java index 285d53f2dc5a..28bb66f39572 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java @@ -18,8 +18,13 @@ package com.android.systemui.statusbar.notification; import android.app.Notification; import android.content.Context; +import android.text.BidiFormatter; +import android.text.Spannable; +import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.text.style.TextAppearanceSpan; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import com.android.systemui.R; @@ -34,12 +39,12 @@ public class HybridNotificationViewManager { private final Context mContext; private ViewGroup mParent; - private String mConcadenationString; + private String mDivider; public HybridNotificationViewManager(Context ctx, ViewGroup parent) { mContext = ctx; mParent = parent; - mConcadenationString = mContext.getString(R.string.group_summary_concadenation); + mDivider = " • "; } private HybridNotificationView inflateHybridView() { @@ -83,7 +88,7 @@ public class HybridNotificationViewManager { if (reusableView == null) { reusableView = inflateHybridView(); } - CharSequence summary = null; + SpannableStringBuilder summary = new SpannableStringBuilder(); int childCount = group.size(); for (int i = startIndex; i < childCount; i++) { ExpandableNotificationRow child = group.get(i); @@ -92,15 +97,18 @@ public class HybridNotificationViewManager { if (titleText == null) { continue; } - if (TextUtils.isEmpty(summary)) { - summary = titleText; - } else if (reusableView.isLayoutRtl()) { - summary = titleText + mConcadenationString + summary; - } else { - summary = summary + mConcadenationString + titleText; + if (!TextUtils.isEmpty(summary)) { + summary.append(mDivider, + new TextAppearanceSpan(mContext, R.style. + TextAppearance_Material_Notification_HybridNotificationDivider), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } + summary.append(BidiFormatter.getInstance().unicodeWrap(titleText)); } - reusableView.bind(summary); + // We want to force the same orientation as the layout RTL mode + BidiFormatter formater = BidiFormatter.getInstance( + reusableView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL); + reusableView.bind(formater.unicodeWrap(summary)); return reusableView; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java new file mode 100644 index 000000000000..487a7a03974e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar.notification; + +import android.content.Context; +import android.service.notification.StatusBarNotification; +import android.view.View; + +import com.android.internal.widget.ImageFloatingTextView; +import com.android.systemui.statusbar.TransformableView; + +/** + * Wraps a notification containing a big text template + */ +public class NotificationBigTextTemplateViewWrapper extends NotificationTemplateViewWrapper { + + private ImageFloatingTextView mBigtext; + + protected NotificationBigTextTemplateViewWrapper(Context ctx, View view) { + super(ctx, view); + } + + private void resolveViews(StatusBarNotification notification) { + mBigtext = (ImageFloatingTextView) mView.findViewById(com.android.internal.R.id.big_text); + } + + @Override + public void notifyContentUpdated(StatusBarNotification notification) { + // Reinspect the notification. Before the super call, because the super call also updates + // the transformation types and we need to have our values set by then. + resolveViews(notification); + super.notifyContentUpdated(notification); + } + + @Override + protected void updateTransformedTypes() { + // This also clears the existing types + super.updateTransformedTypes(); + if (mBigtext != null) { + mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT, + mBigtext); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java index b060245a4fbb..0c21f0b2c962 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java @@ -55,11 +55,12 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp } TransformState otherState = notification.getCurrentState( TRANSFORMING_VIEW_TITLE); - CrossFadeHelper.fadeOut(mText, endRunnable); + final View text = ownState.getTransformedView(); + CrossFadeHelper.fadeOut(text, endRunnable); if (otherState != null) { int[] otherStablePosition = otherState.getLaidOutLocationOnScreen(); int[] ownPosition = ownState.getLaidOutLocationOnScreen(); - mText.animate() + text.animate() .translationY((otherStablePosition[1] + otherState.getTransformedView().getHeight() - ownPosition[1]) * 0.33f) @@ -72,11 +73,11 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp if (endRunnable != null) { endRunnable.run(); } - TransformState.setClippingDeactivated(mText, + TransformState.setClippingDeactivated(text, false); } }); - TransformState.setClippingDeactivated(mText, true); + TransformState.setClippingDeactivated(text, true); otherState.recycle(); } return true; @@ -90,17 +91,18 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp } TransformState otherState = notification.getCurrentState( TRANSFORMING_VIEW_TITLE); - boolean isVisible = mText.getVisibility() == View.VISIBLE; - CrossFadeHelper.fadeIn(mText); + final View text = ownState.getTransformedView(); + boolean isVisible = text.getVisibility() == View.VISIBLE; + CrossFadeHelper.fadeIn(text); if (otherState != null) { int[] otherStablePosition = otherState.getLaidOutLocationOnScreen(); int[] ownStablePosition = ownState.getLaidOutLocationOnScreen(); if (!isVisible) { - mText.setTranslationY((otherStablePosition[1] + text.setTranslationY((otherStablePosition[1] + otherState.getTransformedView().getHeight() - ownStablePosition[1]) * 0.33f); } - mText.animate() + text.animate() .translationY(0) .setDuration( StackStateAnimator.ANIMATION_DURATION_STANDARD) @@ -108,11 +110,11 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp .withEndAction(new Runnable() { @Override public void run() { - TransformState.setClippingDeactivated(mText, + TransformState.setClippingDeactivated(text, false); } }); - TransformState.setClippingDeactivated(mText, true); + TransformState.setClippingDeactivated(text, true); otherState.recycle(); } return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java index f50b9768d270..a2b4c5d24442 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java @@ -37,6 +37,8 @@ public abstract class NotificationViewWrapper implements TransformableView { if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) { if ("bigPicture".equals(v.getTag())) { return new NotificationBigPictureTemplateViewWrapper(ctx, v); + } else if ("bigText".equals(v.getTag())) { + return new NotificationBigTextTemplateViewWrapper(ctx, v); } return new NotificationTemplateViewWrapper(ctx, v); } else if (v instanceof NotificationHeaderView) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java index 9a94d34f7ede..eade2a89447d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java @@ -35,6 +35,7 @@ public abstract class BaseStatusBarHeader extends RelativeLayout implements public abstract int getCollapsedHeight(); public abstract int getExpandedHeight(); + public abstract void setExpanded(boolean b); public abstract void setExpansion(float headerExpansionFraction); public abstract void setListening(boolean listening); 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 a2586f1984f2..bb03454de0f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -304,8 +304,7 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL public void onTuningChanged(String key, String newValue) { switch (key) { case KEY_DOCK_WINDOW_GESTURE: - mDockWindowEnabled = (newValue == null) || - (Integer.parseInt(newValue) != 0); + mDockWindowEnabled = newValue != null && (Integer.parseInt(newValue) != 0); break; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java index 3130eb9c4c2d..d3681b72372b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java @@ -154,10 +154,14 @@ public class NotificationGroupManager implements HeadsUpManager.OnHeadsUpChanged } mBarState = newState; if (mBarState == StatusBarState.KEYGUARD) { - for (NotificationGroup group : mGroupMap.values()) { - if (group.expanded) { - setGroupExpanded(group, false); - } + collapseAllGroups(); + } + } + + public void collapseAllGroups() { + for (NotificationGroup group : mGroupMap.values()) { + if (group.expanded) { + setGroupExpanded(group, false); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 575eda7cf873..f822bd535851 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -39,8 +39,6 @@ import android.view.ViewStub; import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.accessibility.AccessibilityEvent; -import android.view.animation.Interpolator; -import android.view.animation.PathInterpolator; import android.widget.FrameLayout; import android.widget.TextView; @@ -212,10 +210,6 @@ public class NotificationPanelView extends PanelView implements } }; - /** Interpolator to be used for animations that respond directly to a touch */ - private final Interpolator mTouchResponseInterpolator = - new PathInterpolator(0.3f, 0f, 0.1f, 1f); - public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(!DEBUG); @@ -1447,7 +1441,7 @@ public class NotificationPanelView extends PanelView implements mScrollView.setBlockFlinging(true); ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target); if (isClick) { - animator.setInterpolator(mTouchResponseInterpolator); + animator.setInterpolator(Interpolators.TOUCH_RESPONSE); animator.setDuration(368); } else { mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java index cbb71c5d97e6..fd28b095c09d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.phone; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.View; @@ -55,6 +56,20 @@ public class NotificationsQuickSettingsContainer extends FrameLayout } @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + reloadWidth(mScrollView); + reloadWidth(mStackScroller); + } + + private void reloadWidth(View view) { + LayoutParams params = (LayoutParams) view.getLayoutParams(); + params.width = getContext().getResources().getDimensionPixelSize( + R.dimen.notification_panel_width); + view.setLayoutParams(params); + } + + @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); return insets; 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 07dc4fd5fb7c..4dee51df131c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -118,7 +118,10 @@ import com.android.systemui.doze.DozeLog; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.qs.QSPanel; import com.android.systemui.recents.ScreenPinningRequest; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.UndockingTaskEvent; import com.android.systemui.stackdivider.Divider; +import com.android.systemui.stackdivider.WindowManagerProxy; import com.android.systemui.statusbar.ActivatableNotificationView; import com.android.systemui.statusbar.BackDropView; import com.android.systemui.statusbar.BaseStatusBar; @@ -1112,26 +1115,25 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override public boolean onLongClick(View v) { if (mRecents != null) { - Point realSize = new Point(); - mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY) - .getRealSize(realSize); - Rect initialBounds; - - // Hack level over 9000: Make it one pixel smaller so activity manager doesn't - // dismiss it immediately again. Remove once b/26777526 is fixed. - if (mContext.getResources().getConfiguration().orientation - == Configuration.ORIENTATION_LANDSCAPE) { - initialBounds = new Rect(0, 0, realSize.x - 1, realSize.y); + int dockSide = WindowManagerProxy.getInstance().getDockSide(); + if (dockSide == WindowManager.DOCKED_INVALID) { + Point realSize = new Point(); + mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY) + .getRealSize(realSize); + Rect initialBounds= new Rect(0, 0, realSize.x, realSize.y); + boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, + ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, + initialBounds); + if (docked) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS); + return true; + } } else { - initialBounds = new Rect(0, 0, realSize.x, realSize.y - 1); - } - boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, - ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, - initialBounds); - if (docked) { - MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS); + EventBus.getDefault().send(new UndockingTaskEvent()); + MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS); return true; } + } return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java index 9aeb1f8951be..fe463855020a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java @@ -31,7 +31,6 @@ import android.widget.ImageView; import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; - import com.android.keyguard.KeyguardStatusView; import com.android.systemui.R; import com.android.systemui.qs.QSPanel; @@ -74,6 +73,9 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements private float mDateTimeTranslation; private MultiUserSwitch mMultiUserSwitch; private ImageView mMultiUserAvatar; + private View mQsDetailHeaderBack; + + private final int[] mTmpInt2 = new int[2]; public QuickStatusBarHeader(Context context, AttributeSet attrs) { super(context, attrs); @@ -87,6 +89,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements mDateTimeTranslation = mContext.getResources().getDimension( R.dimen.qs_date_anim_translation); mDateTimeGroup = (ViewGroup) findViewById(R.id.date_time_group); + mDateTimeGroup.findViewById(R.id.empty_time_view).setVisibility(View.GONE); mExpandedGroup = (ViewGroup) findViewById(R.id.expanded_group); mHeaderQsPanel = (QuickQSPanel) findViewById(R.id.quick_qs_panel); @@ -100,6 +103,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements mQsDetailHeader = findViewById(R.id.qs_detail_header); mQsDetailHeader.setAlpha(0); + mQsDetailHeaderBack = mQsDetailHeader.findViewById(com.android.internal.R.id.up); mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title); mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle); mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress); @@ -367,6 +371,15 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements } }); } + mQsDetailHeaderBack.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + v.getLocationInWindow(mTmpInt2); + mTmpInt2[0] += v.getWidth() / 2; + mTmpInt2[1] += v.getHeight() / 2; + mQsPanel.showDetailAdapter(false, null, mTmpInt2); + } + }); } else { mQsDetailHeader.setClickable(false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java index b0369368b4b2..500d60359145 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java @@ -20,7 +20,6 @@ public interface HotspotController { void addCallback(Callback callback); void removeCallback(Callback callback); boolean isHotspotEnabled(); - boolean isHotspotSupported(); void setHotspotEnabled(boolean enabled); boolean isTetheringAllowed(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index 61d26c72a898..07b74094ffb2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -27,8 +27,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.Log; -import com.android.settingslib.TetherUtil; - import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -98,11 +96,6 @@ public class HotspotControllerImpl implements HotspotController { } @Override - public boolean isHotspotSupported() { - return TetherUtil.isTetheringSupported(mContext); - } - - @Override public boolean isTetheringAllowed() { return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(mCurrentUser)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java index 409dac102da1..5cfcd8981890 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.stack; import android.content.Context; +import android.content.res.Configuration; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -58,6 +59,7 @@ public class NotificationChildrenContainer extends ViewGroup { private HybridNotificationView mGroupOverflowContainer; private ViewState mGroupOverFlowState; private int mRealHeight; + private int mLayoutDirection = LAYOUT_DIRECTION_UNDEFINED; public NotificationChildrenContainer(Context context) { this(context, null); @@ -209,6 +211,16 @@ public class NotificationChildrenContainer extends ViewGroup { } } + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + int layoutDirection = getLayoutDirection(); + if (layoutDirection != mLayoutDirection) { + updateGroupOverflow(); + mLayoutDirection = layoutDirection; + } + } + private View inflateDivider() { return LayoutInflater.from(mContext).inflate( R.layout.notification_children_divider, this, false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index d6276b86e308..cc0e67df39cb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -1648,6 +1648,9 @@ public class NotificationStackScrollLayout extends ViewGroup bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()); bottom = Math.min(bottom, getHeight()); } + } else if (mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD) { + top = mTopPadding; + bottom = top; } mBackgroundBounds.top = Math.max(0, top); mBackgroundBounds.bottom = Math.min(getHeight(), bottom); @@ -2093,12 +2096,6 @@ public class NotificationStackScrollLayout extends ViewGroup generateAddAnimation(child, false /* fromMoreCard */); updateAnimationState(child); updateChronometerForChild(child); - if (canChildBeDismissed(child)) { - // Make sure the dismissButton is visible and not in the animated state. - // We need to do this to avoid a race where a clearable notification is added after the - // dismiss animation is finished - mDismissView.showClearButton(); - } } private void updateHideSensitiveForChild(View child) { @@ -2608,6 +2605,9 @@ public class NotificationStackScrollLayout extends ViewGroup mIsExpanded = isExpanded; mStackScrollAlgorithm.setIsExpanded(isExpanded); if (changed) { + if (!mIsExpanded) { + mGroupManager.collapseAllGroups(); + } updateNotificationAnimationStates(); updateChronometers(); } @@ -2977,7 +2977,6 @@ public class NotificationStackScrollLayout extends ViewGroup mDismissView.performVisibilityAnimation(false, dimissHideFinishRunnable); } else { dimissHideFinishRunnable.run(); - mDismissView.showClearButton(); } } } @@ -2985,7 +2984,6 @@ public class NotificationStackScrollLayout extends ViewGroup public void setDismissAllInProgress(boolean dismissAllInProgress) { mDismissAllInProgress = dismissAllInProgress; - mDismissView.setDismissAllInProgress(dismissAllInProgress); mAmbientState.setDismissAllInProgress(dismissAllInProgress); if (dismissAllInProgress) { disableClipOptimization(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index bc8c82572c9d..784f610e40a1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -80,10 +80,6 @@ public class TvStatusBar extends BaseStatusBar { boolean showImeSwitcher) { } - @Override - public void toggleRecentApps() { - } - @Override // CommandQueue public void setWindowState(int window, int state) { } diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java index 7b06393d4e4e..d8cf2e2bcbdc 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java @@ -56,7 +56,7 @@ public class ColorMatrixTile extends QSTile<QSTile.State> implements DisplayCont } @Override - protected State newTileState() { + public State newTileState() { return new State(); } diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 0e67a24748b8..e1dd87f55ed4 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -348,5 +348,9 @@ message MetricsEvent { // OS: 6.1 // GMS: 7.8.99 USER_CREDENTIALS = 285; + + // Logged when the user undocks a previously docked window by long pressing recents while in + // docked mode. + ACTION_WINDOW_UNDOCK_LONGPRESS = 286; } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java index 912e8e2eb246..b79a7ba69b4e 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java @@ -25,6 +25,7 @@ import android.gesture.GestureStore; import android.gesture.GestureStroke; import android.gesture.Prediction; import android.util.Slog; +import android.util.TypedValue; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -70,7 +71,7 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen // Indicates that we've collected enough data to be sure it could be a // gesture. - private boolean mGestureConfirmed; + private boolean mGestureStarted; // Indicates that motion events from the second pointer are being checked // for a double tap. @@ -83,47 +84,39 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen // Policy flags of the previous event. private int mPolicyFlags; - // The X of the previous event. - private float mPreviousX; + // These values track the previous point that was saved to use for gesture + // detection. They are only updated when the user moves more than the + // recognition threshold. + private float mPreviousGestureX; + private float mPreviousGestureY; - // The Y of the previous event. - private float mPreviousY; - - // The X of the down event. + // These values track the previous point that was used to determine if there + // was a transition into or out of gesture detection. They are updated when + // the user moves more than the detection threshold. private float mBaseX; - - // The Y of the down event. private float mBaseY; + private long mBaseTime; - // Slop between the first and second tap to be a double tap. - private final int mDoubleTapSlop; - - // The scaled velocity above which we detect gestures. - private final int mScaledGestureDetectionVelocity; + // This is the calculated movement threshold used track if the user is still + // moving their finger. + private final float mGestureDetectionThreshold; // Buffer for storing points for gesture detection. private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100); - // Helper to track gesture velocity. - private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); - // The minimal delta between moves to add a gesture point. private static final int TOUCH_TOLERANCE = 3; // The minimal score for accepting a predicted gesture. private static final float MIN_PREDICTION_SCORE = 2.0f; - // The velocity above which we detect gestures. Expressed in DIPs/Second. - private static final int GESTURE_DETECTION_VELOCITY_DIP = 1000; - - // Constant used to calculate velocity in seconds. - private static final int VELOCITY_UNITS_SECONDS = 1000; + private static final int GESTURE_CONFIRM_MM = 10; + private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 1000; + private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 500; AccessibilityGestureDetector(Context context, Listener listener) { mListener = listener; - mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop(); - mGestureDetector = new GestureDetector(context, this); mGestureDetector.setOnDoubleTapListener(this); @@ -132,15 +125,14 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen mGestureLibrary.setSequenceType(GestureStore.SEQUENCE_SENSITIVE); mGestureLibrary.load(); - final float density = context.getResources().getDisplayMetrics().density; - mScaledGestureDetectionVelocity = (int) (GESTURE_DETECTION_VELOCITY_DIP * density); + mGestureDetectionThreshold = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1, + context.getResources().getDisplayMetrics()) * GESTURE_CONFIRM_MM; } public boolean onMotionEvent(MotionEvent event, int policyFlags) { - mVelocityTracker.addMovement(event); - final float x = event.getX(); final float y = event.getY(); + final long time = event.getEventTime(); mPolicyFlags = policyFlags; switch (event.getActionMasked()) { @@ -148,54 +140,56 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen mDoubleTapDetected = false; mSecondFingerDoubleTap = false; mRecognizingGesture = true; - mGestureConfirmed = false; + mGestureStarted = false; + mPreviousGestureX = x; + mPreviousGestureY = y; + mStrokeBuffer.clear(); + mStrokeBuffer.add(new GesturePoint(x, y, time)); + mBaseX = x; mBaseY = y; - mPreviousX = x; - mPreviousY = y; - mStrokeBuffer.clear(); - mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime())); - mVelocityTracker.clear(); - mVelocityTracker.addMovement(event); + mBaseTime = time; break; case MotionEvent.ACTION_MOVE: if (mRecognizingGesture) { - if (!mGestureConfirmed) { - mVelocityTracker.addMovement(event); - // It is *important* to use the distance traveled by the pointers - // on the screen which may or may not be magnified. - final float deltaX = mBaseX - event.getX(0); - final float deltaY = mBaseY - event.getY(0); - final double moveDelta = Math.hypot(deltaX, deltaY); - // The user has moved enough for us to decide. - if (moveDelta > mDoubleTapSlop) { - // Check whether the user is performing a gesture. We - // detect gestures if the pointer is moving above a - // given velocity. - mVelocityTracker.computeCurrentVelocity(VELOCITY_UNITS_SECONDS); - final float maxAbsVelocity = Math.max( - Math.abs(mVelocityTracker.getXVelocity(0)), - Math.abs(mVelocityTracker.getYVelocity(0))); - if (maxAbsVelocity > mScaledGestureDetectionVelocity) { - // We have to perform gesture detection, so - // notify the listener. - mGestureConfirmed = true; - mListener.onGestureStarted(); - } else { - // This won't match any gesture, so notify the - // listener. - cancelGesture(); - mListener.onGestureCancelled(event, policyFlags); - } + final float deltaX = mBaseX - x; + final float deltaY = mBaseY - y; + final double moveDelta = Math.hypot(deltaX, deltaY); + if (moveDelta > mGestureDetectionThreshold) { + // If the pointer has moved more than the threshold, + // update the stored values. + mBaseX = x; + mBaseY = y; + mBaseTime = time; + + // If this hasn't been confirmed as a gesture yet, send + // the event. + if (!mGestureStarted) { + mGestureStarted = true; + mListener.onGestureStarted(); + } + } else { + final long timeDelta = time - mBaseTime; + final long threshold = mGestureStarted ? + CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS : + CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS; + + // If the pointer hasn't moved for longer than the + // timeout, cancel gesture detection. + if (timeDelta > threshold) { + cancelGesture(); + mListener.onGestureCancelled(event, policyFlags); + return false; } } - final float dX = Math.abs(x - mPreviousX); - final float dY = Math.abs(y - mPreviousY); + + final float dX = Math.abs(x - mPreviousGestureX); + final float dY = Math.abs(y - mPreviousGestureY); if (dX >= TOUCH_TOLERANCE || dY >= TOUCH_TOLERANCE) { - mPreviousX = x; - mPreviousY = y; - mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime())); + mPreviousGestureX = x; + mPreviousGestureY = y; + mStrokeBuffer.add(new GesturePoint(x, y, time)); } } break; @@ -204,8 +198,8 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen if (maybeFinishDoubleTap(event, policyFlags)) { return true; } - if (mGestureConfirmed) { - mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime())); + if (mGestureStarted) { + mStrokeBuffer.add(new GesturePoint(x, y, time)); if (!recognizeGesture()) { mListener.onGestureCancelled(event, policyFlags); @@ -223,7 +217,7 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen // If this was the second finger, attempt to recognize double // taps on it. mSecondFingerDoubleTap = true; - mSecondPointerDownTime = event.getEventTime(); + mSecondPointerDownTime = time; } else { // If there are more than two fingers down, stop watching // for a double tap. @@ -268,8 +262,8 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen mFirstTapDetected = false; mDoubleTapDetected = false; mSecondFingerDoubleTap = false; + mGestureStarted = false; cancelGesture(); - mVelocityTracker.clear(); } public boolean firstTapDetected() { @@ -323,7 +317,7 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen private void cancelGesture() { mRecognizingGesture = false; - mGestureConfirmed = false; + mGestureStarted = false; mStrokeBuffer.clear(); } diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index c535ebdc80a0..5e948b117b4e 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -2166,7 +2166,8 @@ public class BackupManagerService { try { ApplicationInfo app = pkg.applicationInfo; if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) - || app.backupAgentName == null) { + || app.backupAgentName == null + || (app.flags&ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0) { packages.remove(a); } else { diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 5f57a7632db9..46671729a2ef 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -111,8 +111,9 @@ class AlarmManagerService extends SystemService { static final boolean WAKEUP_STATS = false; - private static final Intent NEXT_ALARM_CLOCK_CHANGED_INTENT = new Intent( - AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); + private static final Intent NEXT_ALARM_CLOCK_CHANGED_INTENT = + new Intent(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED) + .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); final LocalLog mLog = new LocalLog(TAG); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 3fd8b40dbc14..430092071d90 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2670,18 +2670,21 @@ public class ConnectivityService extends IConnectivityManager.Stub // if ro.tether.denied = true we default to no tethering // gservices could set the secure setting to 1 though to enable it on a build where it // had previously been turned off. + @Override public boolean isTetheringSupported() { enforceTetherAccessPermission(); int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.TETHER_SUPPORTED, defaultVal) != 0) && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); - return tetherEnabledInSettings && ((mTethering.getTetherableUsbRegexs().length != 0 || + return tetherEnabledInSettings && mUserManager.isAdminUser() && + ((mTethering.getTetherableUsbRegexs().length != 0 || mTethering.getTetherableWifiRegexs().length != 0 || mTethering.getTetherableBluetoothRegexs().length != 0) && mTethering.getUpstreamIfaceTypes().length != 0); } + @Override public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) { ConnectivityManager.enforceTetherChangePermission(mContext); @@ -2692,6 +2695,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mTethering.startTethering(type, receiver, showProvisioningUi); } + @Override public void stopTethering(int type) { ConnectivityManager.enforceTetherChangePermission(mContext); mTethering.stopTethering(type); diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 9bd79c9cf6c9..423ef84dd625 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -1649,6 +1649,7 @@ public class DeviceIdleController extends SystemService // Whoops, there is an upcoming alarm. We don't actually want to go idle. if (mState != STATE_ACTIVE) { becomeActiveLocked("alarm", Process.myUid()); + becomeInactiveIfAppropriateLocked(); } return; } diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java index 4f0d4d951e1c..bef6f0aabf5d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java +++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java @@ -62,7 +62,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_LRU = DEBUG_ALL || false; static final boolean DEBUG_MU = DEBUG_ALL || false; static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false; - static final boolean DEBUG_PAUSE = DEBUG_ALL || false; + static final boolean DEBUG_PAUSE = DEBUG_ALL || true; static final boolean DEBUG_POWER = DEBUG_ALL || false; static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false; static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false; @@ -77,7 +77,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_SERVICE = DEBUG_ALL || false; static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false; static final boolean DEBUG_STACK = DEBUG_ALL || false; - static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false; + static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || true; static final boolean DEBUG_SWITCH = DEBUG_ALL || false; static final boolean DEBUG_TASKS = DEBUG_ALL || false; static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false; @@ -85,7 +85,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false; static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false; static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false; - static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false; + static final boolean DEBUG_VISIBILITY = DEBUG_ALL || true; static final boolean DEBUG_VISIBLE_BEHIND = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false; static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index db710c28661e..c021f4cfccaa 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -252,10 +252,12 @@ import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.LAST_STATIC_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; @@ -600,6 +602,8 @@ public final class ActivityManagerService extends ActivityManagerNative final AppErrors mAppErrors; + boolean mDoingSetFocusedActivity; + public boolean canShowErrorDialogs() { return mShowDialogs && !mSleeping && !mShuttingDown; } @@ -2730,6 +2734,12 @@ public final class ActivityManagerService extends ActivityManagerNative } if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r); + + final boolean wasDoingSetFocusedActivity = mDoingSetFocusedActivity; + if (wasDoingSetFocusedActivity) Slog.w(TAG, + "setFocusedActivityLocked: called recursively, r=" + r + ", reason=" + reason); + mDoingSetFocusedActivity = true; + final ActivityRecord last = mFocusedActivity; mFocusedActivity = r; if (r.task.isApplicationTask()) { @@ -2781,6 +2791,12 @@ public final class ActivityManagerService extends ActivityManagerNative mLastFocusedUserId = mFocusedActivity.userId; } + // Log a warning if the focused app is changed during the process. This could + // indicate a problem of the focus setting logic! + if (mFocusedActivity != r) Slog.w(TAG, + "setFocusedActivityLocked: r=" + r + " but focused to " + mFocusedActivity); + mDoingSetFocusedActivity = wasDoingSetFocusedActivity; + EventLogTags.writeAmFocusedActivity( mFocusedActivity == null ? -1 : mFocusedActivity.userId, mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName, @@ -5303,28 +5319,42 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void killAllBackgroundProcesses() { + killAllBackgroundProcesses(-1); + } + + /** + * Kills all background processes with targetSdkVersion below the specified + * target SDK version. + * + * @param targetSdkVersion the target SDK version below which to kill + * processes, or {@code -1} to kill all processes + */ + private void killAllBackgroundProcesses(int targetSdkVersion) { if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES) != PackageManager.PERMISSION_GRANTED) { - String msg = "Permission Denial: killAllBackgroundProcesses() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() + final String msg = "Permission Denial: killAllBackgroundProcesses() from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES; Slog.w(TAG, msg); throw new SecurityException(msg); } - long callingId = Binder.clearCallingIdentity(); + final long callingId = Binder.clearCallingIdentity(); try { - synchronized(this) { - ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(); + synchronized (this) { + final ArrayList<ProcessRecord> procs = new ArrayList<>(); final int NP = mProcessNames.getMap().size(); - for (int ip=0; ip<NP; ip++) { - SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip); + 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++) { - ProcessRecord app = apps.valueAt(ia); + for (int ia = 0; ia < NA; ia++) { + final ProcessRecord app = apps.valueAt(ia); if (app.persistent) { - // we don't kill persistent processes + // We don't kill persistent processes. + continue; + } + if (targetSdkVersion > 0 + && app.info.targetSdkVersion >= targetSdkVersion) { continue; } if (app.removed) { @@ -5336,11 +5366,13 @@ public final class ActivityManagerService extends ActivityManagerNative } } - int N = procs.size(); - for (int i=0; i<N; i++) { + final int N = procs.size(); + for (int i = 0; i < N; i++) { removeProcessLocked(procs.get(i), false, true, "kill all background"); } + mAllowLowerMemLevel = true; + updateOomAdjLocked(); doLowMemReportIfNeededLocked(null); } @@ -17622,6 +17654,22 @@ public final class ActivityManagerService extends ActivityManagerNative final long origId = Binder.clearCallingIdentity(); final ActivityStack stack = mStackSupervisor.getStack(fromStackId); if (stack != null) { + if (fromStackId == DOCKED_STACK_ID) { + + // We are moving all tasks from the docked stack to the fullscreen stack, which + // is dismissing the docked stack, so resize all other stacks to fullscreen here + // already so we don't end up with resize trashing. + for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { + if (StackId.isResizeableByDockedStack(i)) { + ActivityStack otherStack = mStackSupervisor.getStack(i); + if (otherStack != null) { + mStackSupervisor.resizeStackLocked(i, + null, null, null, PRESERVE_WINDOWS, + true /* allowResizeInDockedMode */); + } + } + } + } final ArrayList<TaskRecord> tasks = stack.getAllTasks(); final int size = tasks.size(); if (onTop) { @@ -17760,7 +17808,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (values.getLocales().size() == 1) { // This is an optimization to avoid the JNI call when the result of // getFirstMatch() does not depend on the supported locales. - locale = values.getLocales().getPrimary(); + locale = values.getLocales().get(0); } else { if (mSupportedSystemLocales == null) { mSupportedSystemLocales = @@ -17811,6 +17859,11 @@ public final class ActivityManagerService extends ActivityManagerNative mHandler.sendMessage(msg); } + final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0; + if (isDensityChange) { + killAllBackgroundProcesses(Build.VERSION_CODES.N); + } + for (int i=mLruProcesses.size()-1; i>=0; i--) { ProcessRecord app = mLruProcesses.get(i); try { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 5a0c1c1bcd72..c352fc819884 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2168,7 +2168,9 @@ final class ActivityStack { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next); // This activity is now becoming visible. - mWindowManager.setAppVisibility(next.appToken, true); + if (!next.visible) { + mWindowManager.setAppVisibility(next.appToken, true); + } // schedule launch ticks to collect information about slow apps. next.startLaunchTickingLocked(); @@ -4304,6 +4306,12 @@ final class ActivityStack { oldTaskOverride = record.task.extractOverrideConfig(record.configuration); } + // Conversely, do the same when going the other direction. + if (Configuration.EMPTY.equals(taskConfig) + && !Configuration.EMPTY.equals(oldTaskOverride)) { + taskConfig = record.task.extractOverrideConfig(record.configuration); + } + // Determine what has changed. May be nothing, if this is a config // that has come back from the app after going idle. In that case // we just want to leave the official config object now in the diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 95bc95a8767a..0b2ff655597d 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -583,7 +583,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } final ActivityRecord r = topRunningActivityLocked(); - if (mService.mFocusedActivity != r) { + if (!mService.mDoingSetFocusedActivity && mService.mFocusedActivity != r) { // The focus activity should always be the top activity in the focused stack. // There will be chaos and anarchy if it isn't... mService.setFocusedActivityLocked(r, reason + " setFocusStack"); @@ -1889,12 +1889,6 @@ public final class ActivityStackSupervisor implements DisplayListener { private void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds) { - if (bounds != null && mWindowManager.isFullscreenBounds(stack.mStackId, bounds)) { - // The bounds passed in corresponds to the fullscreen bounds which we normally - // represent with null. Go ahead and set it to null so that all tasks configuration - // can have the right fullscreen state. - bounds = null; - } bounds = TaskRecord.validateBounds(bounds); mTmpBounds.clear(); @@ -1913,7 +1907,8 @@ public final class ActivityStackSupervisor implements DisplayListener { task.updateOverrideConfiguration(tempRect2); } else { task.updateOverrideConfiguration( - tempTaskBounds != null ? tempTaskBounds : bounds); + tempTaskBounds != null ? tempTaskBounds : bounds, + tempTaskInsetBounds != null ? tempTaskInsetBounds : bounds); } } @@ -2213,9 +2208,9 @@ public final class ActivityStackSupervisor implements DisplayListener { // Temporarily disable resizeablility of task we are moving. We don't want it to be resized // if a docked stack is created below which will lead to the stack we are moving from and // its resizeable tasks being resized. - task.mResizeMode = RESIZE_MODE_UNRESIZEABLE; + task.mTemporarilyUnresizable = true; final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop); - task.mResizeMode = resizeMode; + task.mTemporarilyUnresizable = false; mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop); stack.addTask(task, toTop, reason); @@ -2606,9 +2601,11 @@ public final class ActivityStackSupervisor implements DisplayListener { stack.setVisibleBehindActivity(visible ? r : null); if (!visible) { - // Make the activity immediately above r opaque. + // If there is a translucent home activity, we need to force it stop being translucent, + // because we can't depend on the application to necessarily perform that operation. + // Check out b/14469711 for details. final ActivityRecord next = stack.findNextTranslucentActivity(r); - if (next != null) { + if (next != null && next.isHomeActivity()) { mService.convertFromTranslucent(next.appToken); } } diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index e8476dd6e0ed..10f09775608b 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -16,37 +16,7 @@ package com.android.server.am; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.HOME_STACK_ID; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; -import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; -import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS; -import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; -import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS; -import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; -import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN; -import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; -import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; -import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; - +import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.StackId; @@ -55,6 +25,7 @@ import android.app.ActivityManager.TaskThumbnail; import android.app.ActivityManager.TaskThumbnailInfo; import android.app.ActivityOptions; import android.app.AppGlobals; +import android.app.IActivityManager; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -86,6 +57,37 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Objects; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.HOME_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; +import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; +import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN; +import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; +import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; +import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; + final class TaskRecord { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM; private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; @@ -163,6 +165,8 @@ final class TaskRecord { int mResizeMode; // The resize mode of this task and its activities. // Based on the {@link ActivityInfo#resizeMode} of the root activity. + boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize + // changes on a temporary basis. int mLockTaskMode; // Which tasklock mode to launch this task in. One of // ActivityManager.LOCK_TASK_LAUNCH_MODE_* private boolean mPrivileged; // The root activity application of this task holds @@ -241,6 +245,9 @@ final class TaskRecord { // Bounds of the Task. null for fullscreen tasks. Rect mBounds = null; + private final Rect mTmpRect = new Rect(); + private final Rect mTmpRect2 = new Rect(); + // Last non-fullscreen bounds the task was launched in or resized to. // The information is persisted and used to determine the appropriate stack to launch the // task into on restore. @@ -940,7 +947,7 @@ final class TaskRecord { boolean isResizeable() { return !isHomeTask() && (mService.mForceResizableActivities - || ActivityInfo.isResizeableMode(mResizeMode)); + || ActivityInfo.isResizeableMode(mResizeMode)) && !mTemporarilyUnresizable; } boolean inCropWindowsResizeMode() { @@ -1301,9 +1308,22 @@ final class TaskRecord { /** * Update task's override configuration based on the bounds. + * @param bounds The bounds of the task. * @return Update configuration or null if there is no change. */ Configuration updateOverrideConfiguration(Rect bounds) { + return updateOverrideConfiguration(bounds, null /* insetBounds */); + } + + /** + * Update task's override configuration based on the bounds. + * @param bounds The bounds of the task. + * @param insetBounds The bounds used to calculate the system insets, which is used here to + * subtract the navigation bar/status bar size from the screen size reported + * to the application. See {@link IActivityManager#resizeDockedStack}. + * @return Update configuration or null if there is no change. + */ + Configuration updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) { if (Objects.equals(mBounds, bounds)) { return null; } @@ -1326,7 +1346,12 @@ final class TaskRecord { if (stack == null || StackId.persistTaskBounds(stack.mStackId)) { mLastNonFullscreenBounds = mBounds; } - mOverrideConfig = calculateOverrideConfig(mBounds); + + // Stable insets need to be subtracted because we also subtract it in the fullscreen + // configuration. + mTmpRect.set(bounds); + subtractStableInsets(mTmpRect, insetBounds != null ? insetBounds : mTmpRect); + mOverrideConfig = calculateOverrideConfig(mTmpRect); } if (mFullscreen != oldFullscreen) { @@ -1336,6 +1361,16 @@ final class TaskRecord { return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null; } + private void subtractStableInsets(Rect inOutBounds, Rect inInsetBounds) { + mTmpRect2.set(inInsetBounds); + mService.mWindowManager.subtractStableInsets(mTmpRect2); + int leftInset = mTmpRect2.left - inInsetBounds.left; + int topInset = mTmpRect2.top - inInsetBounds.top; + int rightInset = inInsetBounds.right - mTmpRect2.right; + int bottomInset = inInsetBounds.bottom - mTmpRect2.bottom; + inOutBounds.inset(leftInset, topInset, rightInset, bottomInset); + } + Configuration calculateOverrideConfig(Rect bounds) { final Configuration serviceConfig = mService.mConfiguration; final Configuration config = new Configuration(Configuration.EMPTY); @@ -1351,8 +1386,9 @@ final class TaskRecord { ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout); - config.screenLayout = Configuration.reduceScreenLayout( - sl, config.screenWidthDp, config.screenHeightDp); + int longSize = Math.max(config.screenWidthDp, config.screenHeightDp); + int shortSize = Math.min(config.screenWidthDp, config.screenHeightDp); + config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize); return config; } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 64c0891fde4f..548f563bd6af 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -3889,8 +3889,29 @@ public class AudioService extends IAudioService.Stub { int index; if (mIsMuted) { index = 0; - } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) - || ((device & mFullVolumeDevices) != 0)) { + } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) { + /* Special handling for Bluetooth Absolute Volume scenario + * If we send full audio gain, some accessories are too loud even at its lowest + * volume. We are not able to enumerate all such accessories, so here is the + * workaround from phone side. + * For the lowest volume steps 1 and 2, restrict audio gain to 50% and 75%. + * For volume step 0, set audio gain to 0 as some accessories won't mute on their end. + */ + int i = (getIndex(device) + 5)/10; + if (i == 0) { + // 0% for volume 0 + index = 0; + } else if (i == 1) { + // 50% for volume 1 + index = (int)(mIndexMax * 0.5) /10; + } else if (i == 2) { + // 75% for volume 2 + index = (int)(mIndexMax * 0.75) /10; + } else { + // otherwise, full gain + index = (mIndexMax + 5)/10; + } + } else if ((device & mFullVolumeDevices) != 0) { index = (mIndexMax + 5)/10; } else { index = (getIndex(device) + 5)/10; diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index a73a67a9ca7d..760b21819420 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -451,7 +451,7 @@ public class Tethering extends BaseNetworkObserver { ((BluetoothPan) proxy).setBluetoothTethering(enable); // TODO: Enabling bluetooth tethering can fail asynchronously here. // We should figure out a way to bubble up that failure instead of sending success. - int result = ((BluetoothPan) proxy).isTetheringOn() ? + int result = ((BluetoothPan) proxy).isTetheringOn() == enable ? ConnectivityManager.TETHER_ERROR_NO_ERROR : ConnectivityManager.TETHER_ERROR_MASTER_ERROR; sendTetherResult(receiver, result); 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 be55799dd763..e749433b1e3f 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -349,9 +349,9 @@ public class JobStatus { pw.print(prefix); UserHandle.formatUid(pw, uId); pw.print(" tag="); pw.println(tag); pw.print(prefix); - pw.print("Source: uid="); UserHandle.formatUid(pw, sourceUid); - pw.print(" user="); pw.print(sourceUserId); - pw.print(" pkg="); pw.println(sourcePackageName); + pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid()); + pw.print(" user="); pw.print(getSourceUserId()); + pw.print(" pkg="); pw.println(getSourcePackageName()); pw.print(prefix); pw.println("JobInfo:"); pw.print(prefix); pw.print(" Service: "); pw.println(job.getService().flattenToShortString()); diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 544f25522bf3..7f8099e77f7a 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -192,7 +192,7 @@ import java.util.List; * enforcement. */ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { - private static final String TAG = "NetworkPolicy"; + static final String TAG = "NetworkPolicy"; private static final boolean LOGD = false; private static final boolean LOGV = false; @@ -1689,6 +1689,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } writePolicy = true; } + updateRulesForGlobalChangeLocked(true); // Remove associated UID policies int[] uids = new int[0]; @@ -1862,8 +1863,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist"); synchronized (mRulesLock) { mRestrictBackgroundWhitelistUids.append(uid, true); + updateRulesForGlobalChangeLocked(true); writePolicyLocked(); - // TODO: call other update methods like updateNetworkRulesLocked? } mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0).sendToTarget(); } @@ -1878,9 +1879,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0).sendToTarget(); } - private void removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean writePolicy) { + private void removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean updateNow) { mRestrictBackgroundWhitelistUids.delete(uid); - if (writePolicy) { + if (updateNow) { + updateRulesForGlobalChangeLocked(true); writePolicyLocked(); } } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java index 5830b0e8bfaa..281c3d0a5acb 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java @@ -16,19 +16,24 @@ package com.android.server.net; +import static com.android.server.net.NetworkPolicyManagerService.TAG; + import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; -import android.content.Intent; import android.net.INetworkPolicyManager; +import android.net.NetworkPolicy; import android.os.Binder; import android.os.RemoteException; import android.os.ShellCommand; +import android.util.Log; -public class NetworkPolicyManagerShellCommand extends ShellCommand { +class NetworkPolicyManagerShellCommand extends ShellCommand { final INetworkPolicyManager mInterface; - NetworkPolicyManagerShellCommand(NetworkPolicyManagerService service) { + NetworkPolicyManagerShellCommand(INetworkPolicyManager service) { mInterface = service; } @@ -66,16 +71,24 @@ public class NetworkPolicyManagerShellCommand extends ShellCommand { pw.println(" help"); pw.println(" Print this help text."); pw.println(""); + pw.println(" add restrict-background-whitelist UID"); + pw.println(" Adds a UID to the whitelist for restrict background usage."); + pw.println(" get metered-network ID"); + pw.println(" Checks whether the given non-mobile network is metered or not."); pw.println(" get restrict-background"); pw.println(" Gets the global restrict background usage status."); - pw.println(" set restrict-background BOOLEAN"); - pw.println(" Sets the global restrict background usage status."); + pw.println(" list metered-networks [BOOLEAN]"); + pw.println(" Lists all non-mobile networks and whether they are metered or not."); + pw.println(" If a boolean argument is passed, filters just the metered (or unmetered)"); + pw.println(" networks."); pw.println(" list restrict-background-whitelist"); - pw.println(" Prints UID that are whitelisted for restrict background usage."); - pw.println(" add restrict-background-whitelist UID"); - pw.println(" Adds a UID to the whitelist for restrict background usage."); + pw.println(" Lists UIDs that are whitelisted for restrict background usage."); pw.println(" remove restrict-background-whitelist UID"); pw.println(" Removes a UID from the whitelist for restrict background usage."); + pw.println(" set metered-network ID BOOLEAN"); + pw.println(" Toggles whether the given non-mobile network is metered."); + pw.println(" set restrict-background BOOLEAN"); + pw.println(" Sets the global restrict background usage status."); } private int runGet() throws RemoteException { @@ -86,6 +99,8 @@ public class NetworkPolicyManagerShellCommand extends ShellCommand { return -1; } switch(type) { + case "metered-network": + return getNonMobileMeteredNetwork(); case "restrict-background": return getRestrictBackground(); } @@ -101,6 +116,8 @@ public class NetworkPolicyManagerShellCommand extends ShellCommand { return -1; } switch(type) { + case "metered-network": + return setNonMobileMeteredNetwork(); case "restrict-background": return setRestrictBackground(); } @@ -116,6 +133,8 @@ public class NetworkPolicyManagerShellCommand extends ShellCommand { return -1; } switch(type) { + case "metered-networks": + return listNonMobileMeteredNetworks(); case "restrict-background-whitelist": return runListRestrictBackgroundWhitelist(); } @@ -196,7 +215,12 @@ public class NetworkPolicyManagerShellCommand extends ShellCommand { if (uid < 0) { return uid; } - mInterface.addRestrictBackgroundWhitelistedUid(uid); + final long token = Binder.clearCallingIdentity(); + try { + mInterface.addRestrictBackgroundWhitelistedUid(uid); + } finally { + Binder.restoreCallingIdentity(token); + } return 0; } @@ -205,10 +229,95 @@ public class NetworkPolicyManagerShellCommand extends ShellCommand { if (uid < 0) { return uid; } - mInterface.removeRestrictBackgroundWhitelistedUid(uid); + final long token = Binder.clearCallingIdentity(); + try { + mInterface.removeRestrictBackgroundWhitelistedUid(uid); + } finally { + Binder.restoreCallingIdentity(token); + } return 0; } + private int listNonMobileMeteredNetworks() throws RemoteException { + final PrintWriter pw = getOutPrintWriter(); + final String arg = getNextArg(); + final Boolean filter = arg == null ? null : Boolean.valueOf(arg); + for (NetworkPolicy policy : getNonMobilePolicies()) { + if (filter != null && filter.booleanValue() != policy.metered) { + continue; + } + pw.print(getNetworkId(policy)); + pw.print(';'); + pw.println(policy.metered); + } + return 0; + } + + private int getNonMobileMeteredNetwork() throws RemoteException { + final PrintWriter pw = getOutPrintWriter(); + final String id = getNextArg(); + if (id == null) { + pw.println("Error: didn't specify ID"); + return -1; + } + final List<NetworkPolicy> policies = getNonMobilePolicies(); + for (NetworkPolicy policy: policies) { + if (id.equals(getNetworkId(policy))) { + pw.println(policy.metered); + return 0; + } + } + return 0; + } + + private int setNonMobileMeteredNetwork() throws RemoteException { + final PrintWriter pw = getOutPrintWriter(); + final String id = getNextArg(); + if (id == null) { + pw.println("Error: didn't specify ID"); + return -1; + } + final String arg = getNextArg(); + if (arg == null) { + pw.println("Error: didn't specify BOOLEAN"); + return -1; + } + final boolean metered = Boolean.valueOf(arg); + final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null); + boolean changed = false; + for (NetworkPolicy policy : policies) { + if (policy.template.isMatchRuleMobile() || policy.metered == metered) { + continue; + } + final String networkId = getNetworkId(policy); + if (id.equals(networkId)) { + Log.i(TAG, "Changing " + networkId + " metered status to " + metered); + policy.metered = metered; + changed = true; + } + } + if (changed) { + mInterface.setNetworkPolicies(policies); + } + return 0; + } + + private List<NetworkPolicy> getNonMobilePolicies() throws RemoteException { + final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null); + final List<NetworkPolicy> nonMobilePolicies = new ArrayList<NetworkPolicy>(policies.length); + for (NetworkPolicy policy: policies) { + if (!policy.template.isMatchRuleMobile()) { + nonMobilePolicies.add(policy); + } + } + return nonMobilePolicies; + } + + private String getNetworkId(NetworkPolicy policy) { + // ids are typically enclosed on double quotes (") + return policy.template.getNetworkId().replaceAll("^\"|\"$", ""); + } + private int getNextBooleanArg() { final PrintWriter pw = getOutPrintWriter(); final String arg = getNextArg(); diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index f5da52ee733c..29d52c1739ba 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -250,6 +250,12 @@ abstract public class ManagedServices { rebindServices(); } + public void onUserUnlocked(int user) { + if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user); + rebuildRestoredPackages(); + rebindServices(); + } + public ManagedServiceInfo getServiceFromTokenLocked(IInterface service) { if (service == null) { return null; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 078094cfef7a..bcb2c598c82d 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -816,6 +816,12 @@ public class NotificationManagerService extends SystemService { } else if (action.equals(Intent.ACTION_USER_REMOVED)) { final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); mZenModeHelper.onUserRemoved(user); + } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) { + final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); + mConditionProviders.onUserUnlocked(user); + mListeners.onUserUnlocked(user); + mAssistant.onUserUnlocked(user); + mZenModeHelper.onUserUnlocked(user); } } }; @@ -994,6 +1000,7 @@ public class NotificationManagerService extends SystemService { filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(Intent.ACTION_USER_ADDED); filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(Intent.ACTION_USER_UNLOCKED); filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED); getContext().registerReceiver(mIntentReceiver, filter); diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 1d91fb7d858a..7518c6e316f9 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -16,9 +16,10 @@ package com.android.server.notification; -import static android.media.AudioAttributes.USAGE_ALARM; import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; +import static android.media.AudioAttributes.USAGE_UNKNOWN; +import static android.media.AudioAttributes.USAGE_VIRTUAL_SOURCE; import android.app.AppOpsManager; import android.app.AutomaticZenRule; @@ -34,6 +35,7 @@ import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.database.ContentObserver; +import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioManagerInternal; import android.media.AudioSystem; @@ -192,27 +194,35 @@ public class ZenModeHelper { } public void onUserSwitched(int user) { + loadConfigForUser(user, "onUserSwitched"); + } + + public void onUserRemoved(int user) { + if (user < UserHandle.USER_SYSTEM) return; + if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user); + mConfigs.remove(user); + } + + public void onUserUnlocked(int user) { + loadConfigForUser(user, "onUserUnlocked"); + } + + private void loadConfigForUser(int user, String reason) { if (mUser == user || user < UserHandle.USER_SYSTEM) return; mUser = user; - if (DEBUG) Log.d(TAG, "onUserSwitched u=" + user); + if (DEBUG) Log.d(TAG, reason + " u=" + user); ZenModeConfig config = mConfigs.get(user); if (config == null) { - if (DEBUG) Log.d(TAG, "onUserSwitched: generating default config for user " + user); + if (DEBUG) Log.d(TAG, reason + " generating default config for user " + user); config = mDefaultConfig.copy(); config.user = user; } synchronized (mConfig) { - setConfigLocked(config, "onUserSwitched"); + setConfigLocked(config, reason); } cleanUpZenRules(); } - public void onUserRemoved(int user) { - if (user < UserHandle.USER_SYSTEM) return; - if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user); - mConfigs.remove(user); - } - public int getZenModeListenerInterruptionFilter() { return NotificationManager.zenModeToInterruptionFilter(mZenMode); } @@ -705,15 +715,20 @@ public class ZenModeHelper { // notification restrictions final boolean muteNotifications = mEffectsSuppressed; - applyRestrictions(muteNotifications, USAGE_NOTIFICATION); - // call restrictions final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers; - applyRestrictions(muteCalls, USAGE_NOTIFICATION_RINGTONE); - - // alarm restrictions - final boolean muteAlarms = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; - applyRestrictions(muteAlarms, USAGE_ALARM); + // total silence restrictions + final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; + + for (int i = USAGE_UNKNOWN; i <= USAGE_VIRTUAL_SOURCE; i++) { + if (i == USAGE_NOTIFICATION) { + applyRestrictions(muteNotifications || muteEverything, i); + } else if (i == USAGE_NOTIFICATION_RINGTONE) { + applyRestrictions(muteCalls || muteEverything, i); + } else { + applyRestrictions(muteEverything, i); + } + } } private void applyRestrictions(boolean mute, int usage) { diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 64af21313a1d..a3af561bf44f 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -176,8 +176,14 @@ class PackageDexOptimizer { dexoptNeeded = adjustDexoptNeeded(dexoptNeeded); if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) { - // No dexopt needed and we don't use profiles. Nothing to do. - continue; + if (useProfiles) { + // Profiles may trigger re-compilation. The final decision is taken in + // installd. + dexoptNeeded = DexFile.DEX2OAT_NEEDED; + } else { + // No dexopt needed and we don't use profiles. Nothing to do. + continue; + } } final String dexoptType; String oatDir = null; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 43b82e9fcd11..a92cc31659e6 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -6877,7 +6877,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { final boolean dockedStackVisible = mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID); final boolean freeformStackVisible = mWindowManagerInternal.isStackVisible(FREEFORM_WORKSPACE_STACK_ID); - final boolean forceShowSystemBars = dockedStackVisible || freeformStackVisible; + final boolean resizing = mWindowManagerInternal.isDockedDividerResizing(); + + // We need to force system bars when the docked stack is visible, when the freeform stack + // is visible but also when we are resizing for the transitions when docked stack + // visibility changes. + final boolean forceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing; final boolean forceOpaqueSystemBars = forceShowSystemBars && !mForceStatusBarFromKeyguard; // apply translucent bar vis flags diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index b065e855915d..342c078f8162 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -584,14 +584,14 @@ public final class TvInputManagerService extends SystemService { for (IBinder sessionToken : serviceState.sessionTokens) { SessionState sessionState = userState.sessionStateMap.get(sessionToken); if (sessionState.session == null && (inputId == null - || sessionState.info.getId().equals(inputId))) { + || sessionState.inputId.equals(inputId))) { sessionsToAbort.add(sessionState); } } for (SessionState sessionState : sessionsToAbort) { removeSessionStateLocked(sessionState.sessionToken, sessionState.userId); sendSessionTokenToClientLocked(sessionState.client, - sessionState.info.getId(), null, null, sessionState.seq); + sessionState.inputId, null, null, sessionState.seq); } updateServiceConnectionLocked(serviceState.component, userId); } @@ -601,7 +601,7 @@ public final class TvInputManagerService extends SystemService { UserState userState = getOrCreateUserStateLocked(userId); SessionState sessionState = userState.sessionStateMap.get(sessionToken); if (DEBUG) { - Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.info.getId() + ")"); + Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.inputId + ")"); } InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString()); @@ -611,14 +611,14 @@ public final class TvInputManagerService extends SystemService { // Create a session. When failed, send a null token immediately. try { if (sessionState.isRecordingSession) { - service.createRecordingSession(callback, sessionState.info.getId()); + service.createRecordingSession(callback, sessionState.inputId); } else { - service.createSession(channels[1], callback, sessionState.info.getId()); + service.createSession(channels[1], callback, sessionState.inputId); } } catch (RemoteException e) { Slog.e(TAG, "error in createSession", e); removeSessionStateLocked(sessionToken, userId); - sendSessionTokenToClientLocked(sessionState.client, sessionState.info.getId(), null, + sendSessionTokenToClientLocked(sessionState.client, sessionState.inputId, null, null, sessionState.seq); } channels[1].dispose(); @@ -684,14 +684,11 @@ public final class TvInputManagerService extends SystemService { } } - TvInputInfo info = sessionState.info; - if (info != null) { - ServiceState serviceState = userState.serviceStateMap.get(info.getComponent()); - if (serviceState != null) { - serviceState.sessionTokens.remove(sessionToken); - } + ServiceState serviceState = userState.serviceStateMap.get(sessionState.componentName); + if (serviceState != null) { + serviceState.sessionTokens.remove(sessionToken); } - updateServiceConnectionLocked(sessionState.info.getComponent(), userId); + updateServiceConnectionLocked(sessionState.componentName, userId); // Log the end of watch. SomeArgs args = SomeArgs.obtain(); @@ -707,7 +704,7 @@ public final class TvInputManagerService extends SystemService { sessionState = getSessionStateLocked(sessionState.hardwareSessionToken, Process.SYSTEM_UID, userId); } - ServiceState serviceState = getServiceStateLocked(sessionState.info.getComponent(), userId); + ServiceState serviceState = getServiceStateLocked(sessionState.componentName, userId); if (!serviceState.isHardware) { return; } @@ -1091,8 +1088,9 @@ public final class TvInputManagerService extends SystemService { // Create a new session token and a session state. IBinder sessionToken = new Binder(); - SessionState sessionState = new SessionState(sessionToken, info, - isRecordingSession, client, seq, callingUid, resolvedUserId); + SessionState sessionState = new SessionState(sessionToken, info.getId(), + info.getComponent(), isRecordingSession, client, seq, callingUid, + resolvedUserId); // Add them to the global session state map of the current user. userState.sessionStateMap.put(sessionToken, sessionState); @@ -1273,7 +1271,7 @@ public final class TvInputManagerService extends SystemService { // Log the start of watch. SomeArgs args = SomeArgs.obtain(); - args.arg1 = sessionState.info.getComponent().getPackageName(); + args.arg1 = sessionState.componentName.getPackageName(); args.arg2 = System.currentTimeMillis(); args.arg3 = ContentUris.parseId(channelUri); args.arg4 = params; @@ -1779,10 +1777,10 @@ public final class TvInputManagerService extends SystemService { return false; } for (SessionState sessionState : userState.sessionStateMap.values()) { - if (sessionState.info.getId().equals(inputId) + if (sessionState.inputId.equals(inputId) && sessionState.hardwareSessionToken != null) { hardwareInputId = userState.sessionStateMap.get( - sessionState.hardwareSessionToken).info.getId(); + sessionState.hardwareSessionToken).inputId; break; } } @@ -1918,7 +1916,7 @@ public final class TvInputManagerService extends SystemService { pw.println(entry.getKey() + ": " + session); pw.increaseIndent(); - pw.println("info: " + session.info); + pw.println("inputId: " + session.inputId); pw.println("client: " + session.client); pw.println("seq: " + session.seq); pw.println("callingUid: " + session.callingUid); @@ -2046,7 +2044,8 @@ public final class TvInputManagerService extends SystemService { } private final class SessionState implements IBinder.DeathRecipient { - private final TvInputInfo info; + private final String inputId; + private final ComponentName componentName; private final boolean isRecordingSession; private final ITvInputClient client; private final int seq; @@ -2058,10 +2057,12 @@ public final class TvInputManagerService extends SystemService { // Not null if this session represents an external device connected to a hardware TV input. private IBinder hardwareSessionToken; - private SessionState(IBinder sessionToken, TvInputInfo info, boolean isRecordingSession, - ITvInputClient client, int seq, int callingUid, int userId) { + private SessionState(IBinder sessionToken, String inputId, ComponentName componentName, + boolean isRecordingSession, ITvInputClient client, int seq, int callingUid, + int userId) { this.sessionToken = sessionToken; - this.info = info; + this.inputId = inputId; + this.componentName = componentName; this.isRecordingSession = isRecordingSession; this.client = client; this.seq = seq; @@ -2274,19 +2275,19 @@ public final class TvInputManagerService extends SystemService { @Override public void onSessionCreated(ITvInputSession session, IBinder hardwareSessionToken) { if (DEBUG) { - Slog.d(TAG, "onSessionCreated(inputId=" + mSessionState.info.getId() + ")"); + Slog.d(TAG, "onSessionCreated(inputId=" + mSessionState.inputId + ")"); } synchronized (mLock) { mSessionState.session = session; mSessionState.hardwareSessionToken = hardwareSessionToken; if (session != null && addSessionTokenToClientStateLocked(session)) { sendSessionTokenToClientLocked(mSessionState.client, - mSessionState.info.getId(), mSessionState.sessionToken, mChannels[0], + mSessionState.inputId, mSessionState.sessionToken, mChannels[0], mSessionState.seq); } else { removeSessionStateLocked(mSessionState.sessionToken, mSessionState.userId); sendSessionTokenToClientLocked(mSessionState.client, - mSessionState.info.getId(), null, null, mSessionState.seq); + mSessionState.inputId, null, null, mSessionState.seq); } mChannels[0].dispose(); } diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index 2deb0d51d1a4..2f076d1d69e3 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -36,6 +36,9 @@ public class VrManagerService extends SystemService { public static final String TAG = "VrManagerService"; + private static native void initializeNative(); + private static native void setVrModeNative(boolean enabled); + private final Object mLock = new Object(); private boolean mVrModeEnabled = false; private ArraySet<VrStateListener> mListeners = new ArraySet<>(); @@ -68,6 +71,10 @@ public class VrManagerService extends SystemService { @Override public void onStart() { + synchronized(mLock) { + initializeNative(); + } + publishLocalService(VrManagerInternal.class, new LocalService()); } @@ -89,6 +96,7 @@ public class VrManagerService extends SystemService { mVrModeEnabled = enabled; // Log mode change event. Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled")); + setVrModeNative(mVrModeEnabled); onVrModeChangedLocked(); } } diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index 5f974785b667..1bfdcceca3ec 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -22,6 +22,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.graphics.Rect; import android.util.ArrayMap; @@ -50,13 +51,15 @@ public class BoundsAnimationController { private final Rect mFrom; private final Rect mTo; private final Rect mTmpRect; + private final boolean mMoveToFullScreen; - BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to) { + BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to, boolean moveToFullScreen) { super(); mTarget = target; mFrom = from; mTo = to; mTmpRect = new Rect(); + mMoveToFullScreen = moveToFullScreen; addUpdateListener(this); addListener(this); } @@ -88,6 +91,9 @@ public class BoundsAnimationController { @Override public void onAnimationEnd(Animator animation) { finishAnimation(); + if (mMoveToFullScreen) { + mTarget.moveToFullscreen(); + } } @Override @@ -125,14 +131,25 @@ public class BoundsAnimationController { * necessary cleanup. */ void finishBoundsAnimation(); + + void moveToFullscreen(); + + void getFullScreenBounds(Rect bounds); } - void animateBounds(AnimateBoundsUser target, Rect from, Rect to) { + void animateBounds(final AnimateBoundsUser target, Rect from, Rect to) { + boolean moveToFullscreen = false; + if (to == null) { + to = new Rect(); + target.getFullScreenBounds(to); + moveToFullscreen = true; + } + final BoundsAnimator existing = mRunningAnimations.get(target); if (existing != null) { existing.cancel(); } - BoundsAnimator animator = new BoundsAnimator(target, from, to); + BoundsAnimator animator = new BoundsAnimator(target, from, to, moveToFullscreen); mRunningAnimations.put(target, animator); animator.setFloatValues(0f, 1f); animator.setDuration(DEFAULT_APP_TRANSITION_DURATION); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index be1b85c2f9b5..a06d3fc74393 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -289,11 +289,9 @@ class Task implements DimLayer.DimLayerUser { if (displayContent != null) { displayContent.getLogicalDisplayRect(mTmpRect); rotation = displayContent.getDisplayInfo().rotation; - if (bounds == null) { + mFullscreen = bounds == null; + if (mFullscreen) { bounds = mTmpRect; - mFullscreen = true; - } else { - mFullscreen = mTmpRect.equals(bounds); } } diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 46591312bfc9..40ca1c5a688c 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -255,11 +255,9 @@ public class TaskStack implements DimLayer.DimLayerUser, if (mDisplayContent != null) { mDisplayContent.getLogicalDisplayRect(mTmpRect); rotation = mDisplayContent.getDisplayInfo().rotation; - if (bounds == null) { + mFullscreen = bounds == null; + if (mFullscreen) { bounds = mTmpRect; - mFullscreen = true; - } else { - mFullscreen = mTmpRect.equals(bounds); } } @@ -587,7 +585,8 @@ public class TaskStack implements DimLayer.DimLayerUser, } void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) { - if (!StackId.isResizeableByDockedStack(mStackId) || mDisplayContent == null) { + if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) + || mDisplayContent == null) { outBounds.set(mBounds); return; } @@ -616,8 +615,7 @@ public class TaskStack implements DimLayer.DimLayerUser, mDisplayContent.getLogicalDisplayRect(mTmpRect); dockedStack.getRawBounds(mTmpRect2); - final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP - || dockedSide == DOCKED_LEFT; + final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT; getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2, mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft); @@ -722,6 +720,19 @@ public class TaskStack implements DimLayer.DimLayerUser, } } + void resetDockedStackToMiddle() { + if (mStackId != DOCKED_STACK_ID) { + throw new IllegalStateException("Not a docked stack=" + this); + } + + mService.mDockedStackCreateBounds = null; + + final Rect bounds = new Rect(); + getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/); + mService.mH.obtainMessage(RESIZE_STACK, DOCKED_STACK_ID, + 1 /*allowResizeInDockedMode*/, bounds).sendToTarget(); + } + void detachDisplay() { EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); @@ -865,14 +876,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 (bounds.top - mTmpRect.top < mTmpRect.bottom - bounds.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 (bounds.left - mTmpRect.left < mTmpRect.right - bounds.right) { + if (bounds.left - mTmpRect.left <= mTmpRect.right - bounds.right) { return DOCKED_LEFT; } else { return DOCKED_RIGHT; @@ -927,4 +938,18 @@ public class TaskStack implements DimLayer.DimLayerUser, } } } + + @Override + public void moveToFullscreen() { + try { + mService.mActivityManager.moveTasksToFullscreenStack(mStackId, true); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Override + public void getFullScreenBounds(Rect bounds) { + getDisplayContent().getContentRect(bounds); + } } diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java index 2cf26180441f..d843a8ce398f 100644 --- a/services/core/java/com/android/server/wm/WindowLayersController.java +++ b/services/core/java/com/android/server/wm/WindowLayersController.java @@ -16,12 +16,14 @@ package com.android.server.wm; -import android.app.ActivityManager.StackId; import android.util.Slog; import android.view.Display; import java.io.PrintWriter; +import java.util.ArrayDeque; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -55,10 +57,10 @@ public class WindowLayersController { } private int mHighestApplicationLayer = 0; - private WindowState mPinnedWindow = null; - private WindowState mDockedWindow = null; + private ArrayDeque<WindowState> mPinnedWindows = new ArrayDeque<>(); + private ArrayDeque<WindowState> mDockedWindows = new ArrayDeque<>(); private WindowState mDockDivider = null; - private WindowState mReplacingWindow = null; + private ArrayDeque<WindowState> mReplacingWindows = new ArrayDeque<>(); final void assignLayersLocked(WindowList windows) { if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows, @@ -169,43 +171,54 @@ public class WindowLayersController { private void clear() { mHighestApplicationLayer = 0; - mPinnedWindow = null; - mDockedWindow = null; + mPinnedWindows.clear(); + mDockedWindows.clear(); + mReplacingWindows.clear(); mDockDivider = null; } private void collectSpecialWindows(WindowState w) { if (w.mAttrs.type == TYPE_DOCK_DIVIDER) { mDockDivider = w; - } else { - final TaskStack stack = w.getStack(); - if (stack == null) { - return; - } - if (stack.mStackId == StackId.PINNED_STACK_ID) { - mPinnedWindow = w; - } else if (stack.mStackId == StackId.DOCKED_STACK_ID) { - mDockedWindow = w; - } + return; + } + if (w.mWillReplaceWindow) { + mReplacingWindows.add(w); + } + final TaskStack stack = w.getStack(); + if (stack == null) { + return; + } + if (stack.mStackId == PINNED_STACK_ID) { + mPinnedWindows.add(w); + } else if (stack.mStackId == DOCKED_STACK_ID) { + mDockedWindows.add(w); } } private void adjustSpecialWindows() { int layer = mHighestApplicationLayer + 1; - // For pinned and docked stack window, we want to make them above other windows - // also when these windows are animating. - layer = assignAndIncreaseLayerIfNeeded(mDockedWindow, layer); + // For pinned and docked stack window, we want to make them above other windows also when + // these windows are animating. + while (!mDockedWindows.isEmpty()) { + layer = assignAndIncreaseLayerIfNeeded(mDockedWindows.remove(), layer); + } // Leave some space here so the dim layer while dismissing docked/fullscreen stack has space // below the divider but above the app windows. It needs to be below the divider in because // the divider sometimes overlaps the app windows. layer++; layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer); - // We know that we will be animating a relaunching window in the near future, - // which will receive a z-order increase. We want the replaced window to - // immediately receive the same treatment, e.g. to be above the dock divider. - layer = assignAndIncreaseLayerIfNeeded(mReplacingWindow, layer); - layer = assignAndIncreaseLayerIfNeeded(mPinnedWindow, layer); + // We know that we will be animating a relaunching window in the near future, which will + // receive a z-order increase. We want the replaced window to immediately receive the same + // treatment, e.g. to be above the dock divider. + while (!mReplacingWindows.isEmpty()) { + layer = assignAndIncreaseLayerIfNeeded(mReplacingWindows.remove(), layer); + } + + while (!mPinnedWindows.isEmpty()) { + layer = assignAndIncreaseLayerIfNeeded(mPinnedWindows.remove(), layer); + } } private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) { diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java index 66aa8632b9a2..0979cd32a1e2 100644 --- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java +++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java @@ -35,10 +35,10 @@ public class WindowManagerDebugConfig { static final boolean DEBUG_RESIZE = false; static final boolean DEBUG = false; - static final boolean DEBUG_ADD_REMOVE = true; + static final boolean DEBUG_ADD_REMOVE = false; static final boolean DEBUG_FOCUS = false; static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false; - static final boolean DEBUG_ANIM = true; + static final boolean DEBUG_ANIM = false; static final boolean DEBUG_KEYGUARD = false; static final boolean DEBUG_LAYOUT = false; static final boolean DEBUG_LAYERS = false; @@ -50,7 +50,7 @@ public class WindowManagerDebugConfig { static final boolean DEBUG_ORIENTATION = false; static final boolean DEBUG_APP_ORIENTATION = false; static final boolean DEBUG_CONFIGURATION = false; - static final boolean DEBUG_APP_TRANSITIONS = true; + static final boolean DEBUG_APP_TRANSITIONS = false; static final boolean DEBUG_STARTING_WINDOW = false; static final boolean DEBUG_WALLPAPER = false; static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9f833d12abe6..ae6c89a4d610 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -464,6 +464,8 @@ public class WindowManagerService extends IWindowManager.Stub EmulatorDisplayOverlay mEmulatorDisplayOverlay; final float[] mTmpFloats = new float[9]; + final Rect mTmpRect = new Rect(); + final Rect mTmpRect2 = new Rect(); boolean mDisplayReady; boolean mSafeMode; @@ -2856,6 +2858,9 @@ public class WindowManagerService extends IWindowManager.Stub WindowStateAnimator winAnimator, int attrChanges, int oldVisibility) { result |= !win.isVisibleLw() ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0; if (win.mExiting) { + Slog.d(TAG, "relayoutVisibleWindow: " + win + " mExiting=true, mRemoveOnExit=" + + win.mRemoveOnExit + ", mDestroying=" + win.mDestroying); + winAnimator.cancelExitAnimationForNextAnimationLocked(); win.mExiting = false; } @@ -4842,17 +4847,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - /** Returns true if the input bounds corresponds to the fullscreen bounds the stack is on. */ - public boolean isFullscreenBounds(int stackId, Rect bounds) { - synchronized (mWindowMap) { - final TaskStack stack = mStackIdToStack.get(stackId); - if (stack == null || bounds == null) { - return true; - } - return stack.isFullscreenBounds(bounds); - } - } - /** * Re-sizes a stack and its containing tasks. * @param stackId Id of stack to resize. @@ -5370,8 +5364,18 @@ public class WindowManagerService extends IWindowManager.Stub mWindowPlacerLocked.performSurfacePlacement(); // Notify whether the docked stack exists for the current user - getDefaultDisplayContentLocked().mDividerControllerLocked + final DisplayContent displayContent = getDefaultDisplayContentLocked(); + displayContent.mDividerControllerLocked .notifyDockedStackExistsChanged(hasDockedTasksForUser(newUserId)); + + // If the display is already prepared, update the density. + // Otherwise, we'll update it when it's prepared. + if (mDisplayReady) { + final int forcedDensity = getForcedDisplayDensityForUserLocked(newUserId); + final int targetDensity = forcedDensity != 0 ? forcedDensity + : displayContent.mInitialDisplayDensity; + setForcedDisplayDensityLocked(displayContent, targetDensity); + } } } @@ -8106,7 +8110,9 @@ public class WindowManagerService extends IWindowManager.Stub final WindowState imeWin = mInputMethodWindow; final TaskStack focusedStack = mCurrentFocus != null ? mCurrentFocus.getStack() : null; - if (imeWin != null && focusedStack != null && imeWin.isVisibleNow() + if (imeWin != null && imeWin.isVisibleNow() + && isStackVisibleLocked(DOCKED_STACK_ID) + && focusedStack != null && focusedStack.getDockSide() == DOCKED_BOTTOM){ final ArrayList<TaskStack> stacks = displayContent.getStacks(); for (int i = stacks.size() - 1; i >= 0; --i) { @@ -8365,21 +8371,9 @@ public class WindowManagerService extends IWindowManager.Stub } // Display density. - String densityStr = Settings.Global.getString(mContext.getContentResolver(), - Settings.Global.DISPLAY_DENSITY_FORCED); - if (densityStr == null || densityStr.length() == 0) { - densityStr = SystemProperties.get(DENSITY_OVERRIDE, null); - } - if (densityStr != null && densityStr.length() > 0) { - int density; - try { - density = Integer.parseInt(densityStr); - if (displayContent.mBaseDisplayDensity != density) { - Slog.i(TAG_WM, "FORCED DISPLAY DENSITY: " + density); - displayContent.mBaseDisplayDensity = density; - } - } catch (NumberFormatException ex) { - } + final int density = getForcedDisplayDensityForUserLocked(mCurrentUserId); + if (density != 0) { + displayContent.mBaseDisplayDensity = density; } // Display scaling mode. @@ -8465,8 +8459,9 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayContent displayContent = getDisplayContentLocked(displayId); if (displayContent != null) { setForcedDisplayDensityLocked(displayContent, density); - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density)); + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.DISPLAY_DENSITY_FORCED, + Integer.toString(density), mCurrentUserId); } } } finally { @@ -8474,13 +8469,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - // displayContent must not be null - private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) { - Slog.i(TAG_WM, "Using new display density: " + density); - displayContent.mBaseDisplayDensity = density; - reconfigureDisplayLocked(displayContent); - } - @Override public void clearForcedDisplayDensity(int displayId) { if (mContext.checkCallingOrSelfPermission( @@ -8499,8 +8487,8 @@ public class WindowManagerService extends IWindowManager.Stub if (displayContent != null) { setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity); - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.DISPLAY_DENSITY_FORCED, ""); + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.DISPLAY_DENSITY_FORCED, "", mCurrentUserId); } } } finally { @@ -8508,6 +8496,38 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** + * @param userId the ID of the user + * @return the forced display density for the specified user, if set, or + * {@code 0} if not set + */ + private int getForcedDisplayDensityForUserLocked(int userId) { + String densityStr = Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.DISPLAY_DENSITY_FORCED, userId); + if (densityStr == null || densityStr.length() == 0) { + densityStr = SystemProperties.get(DENSITY_OVERRIDE, null); + } + if (densityStr != null && densityStr.length() > 0) { + try { + return Integer.parseInt(densityStr); + } catch (NumberFormatException ex) { + } + } + return 0; + } + + /** + * Forces the given display to the use the specified density. + * + * @param displayContent the display to modify + * @param density the density in DPI to use + */ + private void setForcedDisplayDensityLocked(@NonNull DisplayContent displayContent, + int density) { + displayContent.mBaseDisplayDensity = density; + reconfigureDisplayLocked(displayContent); + } + // displayContent must not be null private void reconfigureDisplayLocked(DisplayContent displayContent) { // TODO: Multidisplay: for now only use with default display. @@ -10389,8 +10409,28 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void getStableInsets(Rect outInsets) throws RemoteException { synchronized (mWindowMap) { + getStableInsetsLocked(outInsets); + } + } + + private void getStableInsetsLocked(Rect outInsets) { + final DisplayInfo di = getDefaultDisplayInfoLocked(); + mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets); + } + + /** + * Intersects the specified {@code inOutBounds} with the display frame that excludes the stable + * inset areas. + * + * @param inOutBounds The inOutBounds to subtract the stable inset areas from. + */ + public void subtractStableInsets(Rect inOutBounds) { + synchronized (mWindowMap) { + getStableInsetsLocked(mTmpRect2); final DisplayInfo di = getDefaultDisplayInfoLocked(); - mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets); + mTmpRect.set(0, 0, di.logicalWidth, di.logicalHeight); + mTmpRect.inset(mTmpRect2); + inOutBounds.intersect(mTmpRect); } } @@ -10594,5 +10634,12 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerService.this.isStackVisibleLocked(stackId); } } + + @Override + public boolean isDockedDividerResizing() { + synchronized (mWindowMap) { + return getDefaultDisplayContentLocked().getDockedDividerController().isResizing(); + } + } } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 465c7e0937b6..2f916d918974 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -16,8 +16,6 @@ package com.android.server.wm; -import com.android.server.input.InputWindowHandle; - import android.app.ActivityManager; import android.app.AppOpsManager; import android.content.Context; @@ -53,10 +51,13 @@ import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.WindowManagerPolicy; +import com.android.server.input.InputWindowHandle; + import java.io.PrintWriter; import java.util.ArrayList; import static android.app.ActivityManager.StackId; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; @@ -75,8 +76,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; @@ -1608,6 +1609,14 @@ final class WindowState implements WindowManagerPolicy.WindowState { win.mAppToken.appDied = true; } mService.removeWindowLocked(win); + if (win.mAttrs.type == TYPE_DOCK_DIVIDER) { + // The owner of the docked divider died :( We reset the docked stack, + // just in case they have the divider at an unstable position. + final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID); + if (stack != null) { + stack.resetDockedStackToMiddle(); + } + } } else if (mHasSurface) { Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid."); mService.removeWindowLocked(WindowState.this); @@ -2133,7 +2142,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { // background. return (mDisplayContent.mDividerControllerLocked.isResizing() || mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) && - !task.inFreeformWorkspace() && !task.isFullscreen(); + !task.inFreeformWorkspace(); + } void setDragResizing() { @@ -2327,6 +2337,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (mDrawLock != null) { pw.print(prefix); pw.println("mDrawLock=" + mDrawLock); } + if (isDragResizing()) { + pw.print(prefix); pw.println("isDragResizing=" + isDragResizing()); + } + if (computeDragResizing()) { + pw.print(prefix); pw.println("computeDragResizing=" + computeDragResizing()); + } } String makeInputChannelName() { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 1dbca968322c..c7c9cbf3ce0e 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -572,7 +572,8 @@ class WindowStateAnimator { WindowSurfaceController createSurfaceLocked() { final WindowState w = mWin; if (w.hasSavedSurface()) { - Slog.i(TAG, "***** createSurface: " + this + ": called when we had a saved surface"); + if (DEBUG_ANIM) Slog.i(TAG, + "createSurface: " + this + ": called when we had a saved surface"); w.restoreSavedSurface(); return mSurfaceController; } diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index e14cfdf9aac0..3219bfe26aac 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -130,7 +130,7 @@ class WindowSurfaceController { void destroyInTransaction() { // if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(3)); + Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(4)); // } try { mSurfaceControl.destroy(); diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index d1d472179542..4e1b644df368 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -647,14 +647,6 @@ class WindowSurfacePlacer { for (int i = windows.size() - 1; i >= 0; i--) { WindowState w = windows.get(i); - Task task = w.getTask(); - if (task == null && w.getDisplayContent().getHomeStack() == null - && w.getAttrs().type != TYPE_PRIVATE_PRESENTATION) { - // TODO: Understand what the use case is here and see if the conditions can be - // simplified. - continue; - } - final boolean obscuredChanged = w.mObscured != mObscured; // Update effect. diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index d1b864878109..bb571c3d0631 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -28,6 +28,7 @@ LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \ $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \ $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \ + $(LOCAL_REL_DIR)/com_android_server_vr_VrManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \ diff --git a/services/core/jni/com_android_server_vr_VrManagerService.cpp b/services/core/jni/com_android_server_vr_VrManagerService.cpp new file mode 100644 index 000000000000..1aba43b2cd8b --- /dev/null +++ b/services/core/jni/com_android_server_vr_VrManagerService.cpp @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#define LOG_TAG "VrManagerService" + +#include <android_runtime/AndroidRuntime.h> +#include <jni.h> +#include <JNIHelp.h> + +#include <utils/Errors.h> +#include <utils/Log.h> +#include <hardware/hardware.h> +#include <hardware/vr.h> + +namespace android { + +static vr_module_t *gVrHardwareModule = NULL; + + +static void init_native(JNIEnv* /* env */, jclass /* clazz */) { + if (gVrHardwareModule != NULL) { + // This call path should never be hit. + ALOGE("%s: May not initialize VR hardware module more than once!", __FUNCTION__); + return; + } + + int err = hw_get_module(VR_HARDWARE_MODULE_ID, (hw_module_t const**)&gVrHardwareModule); + if (err) { + ALOGW("%s: Could not open VR hardware module, error %s (%d).", __FUNCTION__, + strerror(-err), err); + return; + } + + // Call init method if implemented. + if (gVrHardwareModule->init) { + gVrHardwareModule->init(gVrHardwareModule); + } +} + +static void setVrMode_native(JNIEnv* /* env */, jclass /* clazz */, jboolean enabled) { + if (gVrHardwareModule == NULL) { + // There is no VR hardware module implemented, do nothing. + return; + } + + // Call set_vr_mode method, this must be implemented if the HAL exists. + gVrHardwareModule->set_vr_mode(gVrHardwareModule, static_cast<bool>(enabled)); +} + +static const JNINativeMethod method_table[] = { + { "initializeNative", "()V", (void*)init_native }, + { "setVrModeNative", "(Z)V", (void*)setVrMode_native }, +}; + +int register_android_server_vr_VrManagerService(JNIEnv *env) +{ + return jniRegisterNativeMethods(env, "com/android/server/vr/VrManagerService", + method_table, NELEM(method_table)); +} + +}; // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index a7010bcba5dd..ef5c56c1bcfa 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -35,6 +35,7 @@ int register_android_server_SystemServer(JNIEnv* env); int register_android_server_UsbDeviceManager(JNIEnv* env); int register_android_server_UsbMidiDevice(JNIEnv* env); int register_android_server_UsbHostManager(JNIEnv* env); +int register_android_server_vr_VrManagerService(JNIEnv* env); int register_android_server_VibratorService(JNIEnv* env); int register_android_server_location_GnssLocationProvider(JNIEnv* env); int register_android_server_location_FlpHardwareProvider(JNIEnv* env); @@ -69,6 +70,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_UsbDeviceManager(env); register_android_server_UsbMidiDevice(env); register_android_server_UsbHostManager(env); + register_android_server_vr_VrManagerService(env); register_android_server_VibratorService(env); register_android_server_SystemServer(env); register_android_server_location_GnssLocationProvider(env); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 39c21f1a0cd1..f296d68cedcf 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2053,7 +2053,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { resolveIntent.setComponent(adminName); List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceiversAsUser( resolveIntent, - PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, + PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS | + PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, userHandle); if (infos == null || infos.size() <= 0) { throw new IllegalArgumentException("Unknown admin: " + adminName); @@ -4131,7 +4132,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias, final IBinder response) { // Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers. - if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) { + if (!isCallerWithSystemUid()) { return; } @@ -5859,8 +5860,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null); - if (hasUserSetupCompleted(userHandle) - && !UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) { + if (hasUserSetupCompleted(userHandle) && !isCallerWithSystemUid()) { throw new IllegalStateException("Cannot set the profile owner on a user which is " + "already set-up"); } @@ -5920,8 +5920,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void enforceManageUsers() { final int callingUid = mInjector.binderGetCallingUid(); - if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) - || callingUid == Process.ROOT_UID)) { + if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); } } @@ -5944,8 +5943,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (userHandle == UserHandle.getUserId(callingUid)) { return; } - if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) - || callingUid == Process.ROOT_UID)) { + if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) { mContext.enforceCallingOrSelfPermission(permission, "Must be system or have " + permission + " permission"); } @@ -5963,6 +5961,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private boolean isCallerWithSystemUid() { + return UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID); + } + private int getProfileParentId(int userHandle) { final long ident = mInjector.binderClearCallingIdentity(); try { @@ -6247,7 +6249,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public ComponentName getRestrictionsProvider(int userHandle) { synchronized (this) { - if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) { + if (!isCallerWithSystemUid()) { throw new SecurityException("Only the system can query the permission provider"); } DevicePolicyData userData = getUserData(userHandle); @@ -6320,8 +6322,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * permittedList or are a system app. */ private boolean checkPackagesInPermittedListOrSystem(List<String> enabledPackages, - List<String> permittedList) { - int userIdToCheck = UserHandle.getCallingUserId(); + List<String> permittedList, int userIdToCheck) { long id = mInjector.binderClearCallingIdentity(); try { // If we have an enabled packages list for a managed profile the packages @@ -6388,7 +6389,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { for (AccessibilityServiceInfo service : enabledServices) { enabledPackages.add(service.getResolveInfo().serviceInfo.packageName); } - if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList)) { + if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList, + userId)) { Slog.e(LOG_TAG, "Cannot set permitted accessibility services, " + "because it contains already enabled accesibility services."); return false; @@ -6480,6 +6482,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public boolean isAccessibilityServicePermittedByAdmin(ComponentName who, String packageName, + int userHandle) { + if (!mHasFeature) { + return true; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + Preconditions.checkStringNotEmpty(packageName, "packageName is null"); + if (!isCallerWithSystemUid()){ + throw new SecurityException( + "Only the system can query if an accessibility service is disabled by admin"); + } + synchronized (this) { + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + if (admin.permittedAccessiblityServices == null) { + return true; + } + return checkPackagesInPermittedListOrSystem(Arrays.asList(packageName), + admin.permittedAccessiblityServices, userHandle); + } + } + private boolean checkCallerIsCurrentUserOrProfile() { int callingUserId = UserHandle.getCallingUserId(); long token = mInjector.binderClearCallingIdentity(); @@ -6535,7 +6559,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { for (InputMethodInfo ime : enabledImes) { enabledPackages.add(ime.getPackageName()); } - if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList)) { + if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList, + mInjector.binderGetCallingUserHandle().getIdentifier())) { Slog.e(LOG_TAG, "Cannot set permitted input methods, " + "because it contains already enabled input method."); return false; @@ -6628,6 +6653,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override + public boolean isInputMethodPermittedByAdmin(ComponentName who, String packageName, + int userHandle) { + if (!mHasFeature) { + return true; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + Preconditions.checkStringNotEmpty(packageName, "packageName is null"); + if (!isCallerWithSystemUid()) { + throw new SecurityException( + "Only the system can query if an input method is disabled by admin"); + } + synchronized (this) { + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + if (admin.permittedInputMethods == null) { + return true; + } + return checkPackagesInPermittedListOrSystem(Arrays.asList(packageName), + admin.permittedInputMethods, userHandle); + } + } + + @Override public UserHandle createUser(ComponentName who, String name) { Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { @@ -7424,7 +7471,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userHandle) { - if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) { + if (!isCallerWithSystemUid()) { throw new SecurityException("notifyLockTaskModeChanged can only be called by system"); } synchronized (this) { @@ -8179,7 +8226,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } Preconditions.checkNotNull(who, "ComponentName is null"); - if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) { + if (!isCallerWithSystemUid()) { throw new SecurityException("Only the system can query support message for user"); } synchronized (this) { @@ -8197,7 +8244,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } Preconditions.checkNotNull(who, "ComponentName is null"); - if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) { + if (!isCallerWithSystemUid()) { throw new SecurityException("Only the system can query support message for user"); } synchronized (this) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b64db578decb..0cf93288714f 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -496,6 +496,7 @@ public final class SystemServer { boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false); boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false); boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false); + boolean disableRtt = SystemProperties.getBoolean("config.disable_rtt", false); boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1"); try { @@ -788,7 +789,9 @@ public final class SystemServer { mSystemServiceManager.startService( "com.android.server.wifi.WifiScanningService"); - mSystemServiceManager.startService("com.android.server.wifi.RttService"); + if (!disableRtt) { + mSystemServiceManager.startService("com.android.server.wifi.RttService"); + } if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) || mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) { @@ -1088,7 +1091,9 @@ public final class SystemServer { mSystemServiceManager.startService(TrustManagerService.class); - mSystemServiceManager.startService(FingerprintService.class); + if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { + mSystemServiceManager.startService(FingerprintService.class); + } traceBeginAndSlog("StartBackgroundDexOptService"); try { diff --git a/services/net/java/android/net/apf/ApfGenerator.java b/services/net/java/android/net/apf/ApfGenerator.java new file mode 100644 index 000000000000..96c2ba535dd1 --- /dev/null +++ b/services/net/java/android/net/apf/ApfGenerator.java @@ -0,0 +1,883 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.apf; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * APF assembler/generator. A tool for generating an APF program. + * + * Call add*() functions to add instructions to the program, then call + * {@link generate} to get the APF bytecode for the program. + * + * @hide + */ +public class ApfGenerator { + /** + * This exception is thrown when an attempt is made to generate an illegal instruction. + */ + public static class IllegalInstructionException extends Exception { + IllegalInstructionException(String msg) { + super(msg); + } + } + private enum Opcodes { + LABEL(-1), + LDB(1), // Load 1 byte from immediate offset, e.g. "ldb R0, [5]" + LDH(2), // Load 2 bytes from immediate offset, e.g. "ldh R0, [5]" + LDW(3), // Load 4 bytes from immediate offset, e.g. "ldw R0, [5]" + LDBX(4), // Load 1 byte from immediate offset plus register, e.g. "ldbx R0, [5]R0" + LDHX(5), // Load 2 byte from immediate offset plus register, e.g. "ldhx R0, [5]R0" + LDWX(6), // Load 4 byte from immediate offset plus register, e.g. "ldwx R0, [5]R0" + ADD(7), // Add, e.g. "add R0,5" + MUL(8), // Multiply, e.g. "mul R0,5" + DIV(9), // Divide, e.g. "div R0,5" + AND(10), // And, e.g. "and R0,5" + OR(11), // Or, e.g. "or R0,5" + SH(12), // Left shift, e.g, "sh R0, 5" or "sh R0, -5" (shifts right) + LI(13), // Load immediate, e.g. "li R0,5" (immediate encoded as signed value) + JMP(14), // Jump, e.g. "jmp label" + JEQ(15), // Compare equal and branch, e.g. "jeq R0,5,label" + JNE(16), // Compare not equal and branch, e.g. "jne R0,5,label" + JGT(17), // Compare greater than and branch, e.g. "jgt R0,5,label" + JLT(18), // Compare less than and branch, e.g. "jlt R0,5,label" + JSET(19), // Compare any bits set and branch, e.g. "jset R0,5,label" + JNEBS(20), // Compare not equal byte sequence, e.g. "jnebs R0,5,label,0x1122334455" + EXT(21); // Followed by immediate indicating ExtendedOpcodes. + + final int value; + + private Opcodes(int value) { + this.value = value; + } + } + // Extended opcodes. Primary opcode is Opcodes.EXT. ExtendedOpcodes are encoded in the immediate + // field. + private enum ExtendedOpcodes { + LDM(0), // Load from memory, e.g. "ldm R0,5" + STM(16), // Store to memory, e.g. "stm R0,5" + NOT(32), // Not, e.g. "not R0" + NEG(33), // Negate, e.g. "neg R0" + SWAP(34), // Swap, e.g. "swap R0,R1" + MOVE(35); // Move, e.g. "move R0,R1" + + final int value; + + private ExtendedOpcodes(int value) { + this.value = value; + } + } + public enum Register { + R0(0), + R1(1); + + final int value; + + private Register(int value) { + this.value = value; + } + } + private class Instruction { + private final byte mOpcode; // A "Opcode" value. + private final byte mRegister; // A "Register" value. + private boolean mHasImm; + private byte mImmSize; + private boolean mImmSigned; + private int mImm; + // When mOpcode is a jump: + private byte mTargetLabelSize; + private String mTargetLabel; + // When mOpcode == Opcodes.LABEL: + private String mLabel; + // When mOpcode == Opcodes.JNEBS: + private byte[] mCompareBytes; + // Offset in bytes from the begining of this program. Set by {@link ApfGenerator#generate}. + int offset; + + Instruction(Opcodes opcode, Register register) { + mOpcode = (byte)opcode.value; + mRegister = (byte)register.value; + } + + Instruction(Opcodes opcode) { + this(opcode, Register.R0); + } + + void setImm(int imm, boolean signed) { + mHasImm = true; + mImm = imm; + mImmSigned = signed; + mImmSize = calculateImmSize(imm, signed); + } + + void setUnsignedImm(int imm) { + setImm(imm, false); + } + + void setSignedImm(int imm) { + setImm(imm, true); + } + + void setLabel(String label) throws IllegalInstructionException { + if (mLabels.containsKey(label)) { + throw new IllegalInstructionException("duplicate label " + label); + } + if (mOpcode != Opcodes.LABEL.value) { + throw new IllegalStateException("adding label to non-label instruction"); + } + mLabel = label; + mLabels.put(label, this); + } + + void setTargetLabel(String label) { + mTargetLabel = label; + mTargetLabelSize = 4; // May shrink later on in generate(). + } + + void setCompareBytes(byte[] bytes) { + if (mOpcode != Opcodes.JNEBS.value) { + throw new IllegalStateException("adding compare bytes to non-JNEBS instruction"); + } + mCompareBytes = bytes; + } + + /** + * @return size of instruction in bytes. + */ + int size() { + if (mOpcode == Opcodes.LABEL.value) { + return 0; + } + int size = 1; + if (mHasImm) { + size += generatedImmSize(); + } + if (mTargetLabel != null) { + size += generatedImmSize(); + } + if (mCompareBytes != null) { + size += mCompareBytes.length; + } + return size; + } + + /** + * Resize immediate value field so that it's only as big as required to + * contain the offset of the jump destination. + * @return {@code true} if shrunk. + */ + boolean shrink() throws IllegalInstructionException { + if (mTargetLabel == null) { + return false; + } + int oldSize = size(); + int oldTargetLabelSize = mTargetLabelSize; + mTargetLabelSize = calculateImmSize(calculateTargetLabelOffset(), false); + if (mTargetLabelSize > oldTargetLabelSize) { + throw new IllegalStateException("instruction grew"); + } + return size() < oldSize; + } + + /** + * Assemble value for instruction size field. + */ + private byte generateImmSizeField() { + byte immSize = generatedImmSize(); + // Encode size field to fit in 2 bits: 0->0, 1->1, 2->2, 3->4. + return immSize == 4 ? 3 : immSize; + } + + /** + * Assemble first byte of generated instruction. + */ + private byte generateInstructionByte() { + byte sizeField = generateImmSizeField(); + return (byte)((mOpcode << 3) | (sizeField << 1) | mRegister); + } + + /** + * Write {@code value} at offset {@code writingOffset} into {@code bytecode}. + * {@link generatedImmSize} bytes are written. {@code value} is truncated to + * {@code generatedImmSize} bytes. {@code value} is treated simply as a + * 32-bit value, so unsigned values should be zero extended and the truncation + * should simply throw away their zero-ed upper bits, and signed values should + * be sign extended and the truncation should simply throw away their signed + * upper bits. + */ + private int writeValue(int value, byte[] bytecode, int writingOffset) { + for (int i = generatedImmSize() - 1; i >= 0; i--) { + bytecode[writingOffset++] = (byte)((value >> (i * 8)) & 255); + } + return writingOffset; + } + + /** + * Generate bytecode for this instruction at offset {@link offset}. + */ + void generate(byte[] bytecode) throws IllegalInstructionException { + if (mOpcode == Opcodes.LABEL.value) { + return; + } + int writingOffset = offset; + bytecode[writingOffset++] = generateInstructionByte(); + if (mTargetLabel != null) { + writingOffset = writeValue(calculateTargetLabelOffset(), bytecode, writingOffset); + } + if (mHasImm) { + writingOffset = writeValue(mImm, bytecode, writingOffset); + } + if (mCompareBytes != null) { + System.arraycopy(mCompareBytes, 0, bytecode, writingOffset, mCompareBytes.length); + writingOffset += mCompareBytes.length; + } + if ((writingOffset - offset) != size()) { + throw new IllegalStateException("wrote " + (writingOffset - offset) + + " but should have written " + size()); + } + } + + /** + * Calculate the size of either the immediate field or the target label field, if either is + * present. Most instructions have either an immediate or a target label field, but for the + * instructions that have both, the size of the target label field must be the same as the + * size of the immediate field, because there is only one length field in the instruction + * byte, hence why this function simply takes the maximum of the two sizes, so neither is + * truncated. + */ + private byte generatedImmSize() { + return mImmSize > mTargetLabelSize ? mImmSize : mTargetLabelSize; + } + + private int calculateTargetLabelOffset() throws IllegalInstructionException { + Instruction targetLabelInstruction; + if (mTargetLabel == DROP_LABEL) { + targetLabelInstruction = mDropLabel; + } else if (mTargetLabel == PASS_LABEL) { + targetLabelInstruction = mPassLabel; + } else { + targetLabelInstruction = mLabels.get(mTargetLabel); + } + if (targetLabelInstruction == null) { + throw new IllegalInstructionException("label not found: " + mTargetLabel); + } + // Calculate distance from end of this instruction to instruction.offset. + final int targetLabelOffset = targetLabelInstruction.offset - (offset + size()); + if (targetLabelOffset < 0) { + throw new IllegalInstructionException("backward branches disallowed; label: " + + mTargetLabel); + } + return targetLabelOffset; + } + + private byte calculateImmSize(int imm, boolean signed) { + if (imm == 0) { + return 0; + } + if (signed && (imm >= -128 && imm <= 127) || + !signed && (imm >= 0 && imm <= 255)) { + return 1; + } + if (signed && (imm >= -32768 && imm <= 32767) || + !signed && (imm >= 0 && imm <= 65535)) { + return 2; + } + return 4; + } + } + + /** + * Jump to this label to terminate the program and indicate the packet + * should be dropped. + */ + public static final String DROP_LABEL = "__DROP__"; + + /** + * Jump to this label to terminate the program and indicate the packet + * should be passed to the AP. + */ + public static final String PASS_LABEL = "__PASS__"; + + /** + * Number of memory slots available for access via APF stores to memory and loads from memory. + * The memory slots are numbered 0 to {@code MEMORY_SLOTS} - 1. This must be kept in sync with + * the APF interpreter. + */ + public static final int MEMORY_SLOTS = 16; + + /** + * Memory slot number that is prefilled with the IPv4 header length. + * Note that this memory slot may be overwritten by a program that + * executes stores to this memory slot. This must be kept in sync with + * the APF interpreter. + */ + public static final int IPV4_HEADER_SIZE_MEMORY_SLOT = 13; + + /** + * Memory slot number that is prefilled with the size of the packet being filtered in bytes. + * Note that this memory slot may be overwritten by a program that + * executes stores to this memory slot. This must be kept in sync with the APF interpreter. + */ + public static final int PACKET_SIZE_MEMORY_SLOT = 14; + + /** + * Memory slot number that is prefilled with the age of the filter in seconds. The age of the + * filter is the time since the filter was installed until now. + * Note that this memory slot may be overwritten by a program that + * executes stores to this memory slot. This must be kept in sync with the APF interpreter. + */ + public static final int FILTER_AGE_MEMORY_SLOT = 15; + + /** + * First memory slot containing prefilled values. Can be used in range comparisons to determine + * if memory slot index is within prefilled slots. + */ + public static final int FIRST_PREFILLED_MEMORY_SLOT = IPV4_HEADER_SIZE_MEMORY_SLOT; + + /** + * Last memory slot containing prefilled values. Can be used in range comparisons to determine + * if memory slot index is within prefilled slots. + */ + public static final int LAST_PREFILLED_MEMORY_SLOT = FILTER_AGE_MEMORY_SLOT; + + private final ArrayList<Instruction> mInstructions = new ArrayList<Instruction>(); + private final HashMap<String, Instruction> mLabels = new HashMap<String, Instruction>(); + private final Instruction mDropLabel = new Instruction(Opcodes.LABEL); + private final Instruction mPassLabel = new Instruction(Opcodes.LABEL); + private boolean mGenerated; + + /** + * Set version of APF instruction set to generate instructions for. Returns {@code true} + * if generating for this version is supported, {@code false} otherwise. + */ + public boolean setApfVersion(int version) { + // This version number syncs up with APF_VERSION in hardware/google/apf/apf_interpreter.h + return version == 2; + } + + private void addInstruction(Instruction instruction) { + if (mGenerated) { + throw new IllegalStateException("Program already generated"); + } + mInstructions.add(instruction); + } + + /** + * Define a label at the current end of the program. Jumps can jump to this label. Labels are + * their own separate instructions, though with size 0. This facilitates having labels with + * no corresponding code to execute, for example a label at the end of a program. For example + * an {@link ApfGenerator} might be passed to a function that adds a filter like so: + * <pre> + * load from packet + * compare loaded data, jump if not equal to "next_filter" + * load from packet + * compare loaded data, jump if not equal to "next_filter" + * jump to drop label + * define "next_filter" here + * </pre> + * In this case "next_filter" may not have any generated code associated with it. + */ + public ApfGenerator defineLabel(String name) throws IllegalInstructionException { + Instruction instruction = new Instruction(Opcodes.LABEL); + instruction.setLabel(name); + addInstruction(instruction); + return this; + } + + /** + * Add an unconditional jump instruction to the end of the program. + */ + public ApfGenerator addJump(String target) { + Instruction instruction = new Instruction(Opcodes.JMP); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to load the byte at offset {@code offset} + * bytes from the begining of the packet into {@code register}. + */ + public ApfGenerator addLoad8(Register register, int offset) { + Instruction instruction = new Instruction(Opcodes.LDB, register); + instruction.setUnsignedImm(offset); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to load 16-bits at offset {@code offset} + * bytes from the begining of the packet into {@code register}. + */ + public ApfGenerator addLoad16(Register register, int offset) { + Instruction instruction = new Instruction(Opcodes.LDH, register); + instruction.setUnsignedImm(offset); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to load 32-bits at offset {@code offset} + * bytes from the begining of the packet into {@code register}. + */ + public ApfGenerator addLoad32(Register register, int offset) { + Instruction instruction = new Instruction(Opcodes.LDW, register); + instruction.setUnsignedImm(offset); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to load a byte from the packet into + * {@code register}. The offset of the loaded byte from the begining of the packet is + * the sum of {@code offset} and the value in register R1. + */ + public ApfGenerator addLoad8Indexed(Register register, int offset) { + Instruction instruction = new Instruction(Opcodes.LDBX, register); + instruction.setUnsignedImm(offset); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to load 16-bits from the packet into + * {@code register}. The offset of the loaded 16-bits from the begining of the packet is + * the sum of {@code offset} and the value in register R1. + */ + public ApfGenerator addLoad16Indexed(Register register, int offset) { + Instruction instruction = new Instruction(Opcodes.LDHX, register); + instruction.setUnsignedImm(offset); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to load 32-bits from the packet into + * {@code register}. The offset of the loaded 32-bits from the begining of the packet is + * the sum of {@code offset} and the value in register R1. + */ + public ApfGenerator addLoad32Indexed(Register register, int offset) { + Instruction instruction = new Instruction(Opcodes.LDWX, register); + instruction.setUnsignedImm(offset); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to add {@code value} to register R0. + */ + public ApfGenerator addAdd(int value) { + Instruction instruction = new Instruction(Opcodes.ADD); + instruction.setSignedImm(value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to multiply register R0 by {@code value}. + */ + public ApfGenerator addMul(int value) { + Instruction instruction = new Instruction(Opcodes.MUL); + instruction.setSignedImm(value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to divide register R0 by {@code value}. + */ + public ApfGenerator addDiv(int value) { + Instruction instruction = new Instruction(Opcodes.DIV); + instruction.setSignedImm(value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to logically and register R0 with {@code value}. + */ + public ApfGenerator addAnd(int value) { + Instruction instruction = new Instruction(Opcodes.AND); + instruction.setUnsignedImm(value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to logically or register R0 with {@code value}. + */ + public ApfGenerator addOr(int value) { + Instruction instruction = new Instruction(Opcodes.OR); + instruction.setUnsignedImm(value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to shift left register R0 by {@code value} bits. + */ + public ApfGenerator addLeftShift(int value) { + Instruction instruction = new Instruction(Opcodes.SH); + instruction.setSignedImm(value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to shift right register R0 by {@code value} + * bits. + */ + public ApfGenerator addRightShift(int value) { + Instruction instruction = new Instruction(Opcodes.SH); + instruction.setSignedImm(-value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to add register R1 to register R0. + */ + public ApfGenerator addAddR1() { + Instruction instruction = new Instruction(Opcodes.ADD, Register.R1); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to multiply register R0 by register R1. + */ + public ApfGenerator addMulR1() { + Instruction instruction = new Instruction(Opcodes.MUL, Register.R1); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to divide register R0 by register R1. + */ + public ApfGenerator addDivR1() { + Instruction instruction = new Instruction(Opcodes.DIV, Register.R1); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to logically and register R0 with register R1 + * and store the result back into register R0. + */ + public ApfGenerator addAndR1() { + Instruction instruction = new Instruction(Opcodes.AND, Register.R1); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to logically or register R0 with register R1 + * and store the result back into register R0. + */ + public ApfGenerator addOrR1() { + Instruction instruction = new Instruction(Opcodes.OR, Register.R1); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to shift register R0 left by the value in + * register R1. + */ + public ApfGenerator addLeftShiftR1() { + Instruction instruction = new Instruction(Opcodes.SH, Register.R1); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to move {@code value} into {@code register}. + */ + public ApfGenerator addLoadImmediate(Register register, int value) { + Instruction instruction = new Instruction(Opcodes.LI, register); + instruction.setSignedImm(value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to jump to {@code target} if register R0's + * value equals {@code value}. + */ + public ApfGenerator addJumpIfR0Equals(int value, String target) { + Instruction instruction = new Instruction(Opcodes.JEQ); + instruction.setUnsignedImm(value); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to jump to {@code target} if register R0's + * value does not equal {@code value}. + */ + public ApfGenerator addJumpIfR0NotEquals(int value, String target) { + Instruction instruction = new Instruction(Opcodes.JNE); + instruction.setUnsignedImm(value); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to jump to {@code target} if register R0's + * value is greater than {@code value}. + */ + public ApfGenerator addJumpIfR0GreaterThan(int value, String target) { + Instruction instruction = new Instruction(Opcodes.JGT); + instruction.setUnsignedImm(value); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to jump to {@code target} if register R0's + * value is less than {@code value}. + */ + public ApfGenerator addJumpIfR0LessThan(int value, String target) { + Instruction instruction = new Instruction(Opcodes.JLT); + instruction.setUnsignedImm(value); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to jump to {@code target} if register R0's + * value has any bits set that are also set in {@code value}. + */ + public ApfGenerator addJumpIfR0AnyBitsSet(int value, String target) { + Instruction instruction = new Instruction(Opcodes.JSET); + instruction.setUnsignedImm(value); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + /** + * Add an instruction to the end of the program to jump to {@code target} if register R0's + * value equals register R1's value. + */ + public ApfGenerator addJumpIfR0EqualsR1(String target) { + Instruction instruction = new Instruction(Opcodes.JEQ, Register.R1); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to jump to {@code target} if register R0's + * value does not equal register R1's value. + */ + public ApfGenerator addJumpIfR0NotEqualsR1(String target) { + Instruction instruction = new Instruction(Opcodes.JNE, Register.R1); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to jump to {@code target} if register R0's + * value is greater than register R1's value. + */ + public ApfGenerator addJumpIfR0GreaterThanR1(String target) { + Instruction instruction = new Instruction(Opcodes.JGT, Register.R1); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to jump to {@code target} if register R0's + * value is less than register R1's value. + */ + public ApfGenerator addJumpIfR0LessThanR1(String target) { + Instruction instruction = new Instruction(Opcodes.JLT, Register.R1); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to jump to {@code target} if register R0's + * value has any bits set that are also set in R1's value. + */ + public ApfGenerator addJumpIfR0AnyBitsSetR1(String target) { + Instruction instruction = new Instruction(Opcodes.JSET, Register.R1); + instruction.setTargetLabel(target); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to jump to {@code target} if the bytes of the + * packet at, an offset specified by {@code register}, match {@code bytes}. + */ + public ApfGenerator addJumpIfBytesNotEqual(Register register, byte[] bytes, String target) { + Instruction instruction = new Instruction(Opcodes.JNEBS, register); + instruction.setUnsignedImm(bytes.length); + instruction.setTargetLabel(target); + instruction.setCompareBytes(bytes); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to load memory slot {@code slot} into + * {@code register}. + */ + public ApfGenerator addLoadFromMemory(Register register, int slot) + throws IllegalInstructionException { + if (slot < 0 || slot > (MEMORY_SLOTS - 1)) { + throw new IllegalInstructionException("illegal memory slot number: " + slot); + } + Instruction instruction = new Instruction(Opcodes.EXT, register); + instruction.setUnsignedImm(ExtendedOpcodes.LDM.value + slot); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to store {@code register} into memory slot + * {@code slot}. + */ + public ApfGenerator addStoreToMemory(Register register, int slot) + throws IllegalInstructionException { + if (slot < 0 || slot > (MEMORY_SLOTS - 1)) { + throw new IllegalInstructionException("illegal memory slot number: " + slot); + } + Instruction instruction = new Instruction(Opcodes.EXT, register); + instruction.setUnsignedImm(ExtendedOpcodes.STM.value + slot); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to logically not {@code register}. + */ + public ApfGenerator addNot(Register register) { + Instruction instruction = new Instruction(Opcodes.EXT, register); + instruction.setUnsignedImm(ExtendedOpcodes.NOT.value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to negate {@code register}. + */ + public ApfGenerator addNeg(Register register) { + Instruction instruction = new Instruction(Opcodes.EXT, register); + instruction.setUnsignedImm(ExtendedOpcodes.NEG.value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to swap the values in register R0 and register R1. + */ + public ApfGenerator addSwap() { + Instruction instruction = new Instruction(Opcodes.EXT); + instruction.setUnsignedImm(ExtendedOpcodes.SWAP.value); + addInstruction(instruction); + return this; + } + + /** + * Add an instruction to the end of the program to move the value into + * {@code register} from the other register. + */ + public ApfGenerator addMove(Register register) { + Instruction instruction = new Instruction(Opcodes.EXT, register); + instruction.setUnsignedImm(ExtendedOpcodes.MOVE.value); + addInstruction(instruction); + return this; + } + + /** + * Updates instruction offset fields using latest instruction sizes. + * @return current program length in bytes. + */ + private int updateInstructionOffsets() { + int offset = 0; + for (Instruction instruction : mInstructions) { + instruction.offset = offset; + offset += instruction.size(); + } + return offset; + } + + /** + * Returns an overestimate of the size of the generated program. {@link #generate} may return + * a program that is smaller. + */ + public int programLengthOverEstimate() { + return updateInstructionOffsets(); + } + + /** + * Generate the bytecode for the APF program. + * @return the bytecode. + * @throws IllegalStateException if a label is referenced but not defined. + */ + public byte[] generate() throws IllegalInstructionException { + // Enforce that we can only generate once because we cannot unshrink instructions and + // PASS/DROP labels may move further away requiring unshrinking if we add further + // instructions. + if (mGenerated) { + throw new IllegalStateException("Can only generate() once!"); + } + mGenerated = true; + int total_size; + boolean shrunk; + // Shrink the immediate value fields of instructions. + // As we shrink the instructions some branch offset + // fields may shrink also, thereby shrinking the + // instructions further. Loop until we've reached the + // minimum size. Rarely will this loop more than a few times. + // Limit iterations to avoid O(n^2) behavior. + int iterations_remaining = 10; + do { + total_size = updateInstructionOffsets(); + // Update drop and pass label offsets. + mDropLabel.offset = total_size + 1; + mPassLabel.offset = total_size; + // Limit run-time in aberant circumstances. + if (iterations_remaining-- == 0) break; + // Attempt to shrink instructions. + shrunk = false; + for (Instruction instruction : mInstructions) { + if (instruction.shrink()) { + shrunk = true; + } + } + } while (shrunk); + // Generate bytecode for instructions. + byte[] bytecode = new byte[total_size]; + for (Instruction instruction : mInstructions) { + instruction.generate(bytecode); + } + return bytecode; + } +} + diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index 3ad26d38abaa..7d7be07443c0 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -1,3 +1,7 @@ +######################################################################### +# Build FrameworksServicesTests package +######################################################################### + LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) @@ -22,5 +26,38 @@ LOCAL_PACKAGE_NAME := FrameworksServicesTests LOCAL_CERTIFICATE := platform +LOCAL_JNI_SHARED_LIBRARIES := \ + libapfjni \ + libnativehelper + include $(BUILD_PACKAGE) +######################################################################### +# Build JNI Shared Library +######################################################################### + +LOCAL_PATH:= $(LOCAL_PATH)/jni + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_CFLAGS := -Wall -Werror + +LOCAL_C_INCLUDES := \ + libpcap \ + hardware/google/apf + +LOCAL_SRC_FILES := apf_jni.cpp + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper \ + liblog + +LOCAL_STATIC_LIBRARIES := \ + libpcap \ + libapf + +LOCAL_MODULE := libapfjni + +include $(BUILD_SHARED_LIBRARY) diff --git a/services/tests/servicestests/jni/apf_jni.cpp b/services/tests/servicestests/jni/apf_jni.cpp new file mode 100644 index 000000000000..7d142eb76b95 --- /dev/null +++ b/services/tests/servicestests/jni/apf_jni.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2016, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <JNIHelp.h> +#include <ScopedUtfChars.h> +#include <jni.h> +#include <pcap.h> +#include <stdlib.h> +#include <string> +#include <utils/Log.h> + +#include "apf_interpreter.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +// JNI function acting as simply call-through to native APF interpreter. +static jint com_android_server_ApfTest_apfSimulate( + JNIEnv* env, jclass, jbyteArray program, jbyteArray packet, jint filter_age) { + return accept_packet( + (uint8_t*)env->GetByteArrayElements(program, NULL), + env->GetArrayLength(program), + (uint8_t*)env->GetByteArrayElements(packet, NULL), + env->GetArrayLength(packet), + filter_age); +} + +class ScopedPcap { + public: + ScopedPcap(pcap_t* pcap) : pcap_ptr(pcap) {} + ~ScopedPcap() { + pcap_close(pcap_ptr); + } + + pcap_t* get() const { return pcap_ptr; }; + private: + pcap_t* const pcap_ptr; +}; + +class ScopedFILE { + public: + ScopedFILE(FILE* fp) : file(fp) {} + ~ScopedFILE() { + fclose(file); + } + + FILE* get() const { return file; }; + private: + FILE* const file; +}; + +static void throwException(JNIEnv* env, const std::string& error) { + jclass newExcCls = env->FindClass("java/lang/IllegalStateException"); + if (newExcCls == 0) { + abort(); + return; + } + env->ThrowNew(newExcCls, error.c_str()); +} + +static jstring com_android_server_ApfTest_compileToBpf(JNIEnv* env, jclass, jstring jfilter) { + ScopedUtfChars filter(env, jfilter); + std::string bpf_string; + ScopedPcap pcap(pcap_open_dead(DLT_EN10MB, 65535)); + if (pcap.get() == NULL) { + throwException(env, "pcap_open_dead failed"); + return NULL; + } + + // Compile "filter" to a BPF program + bpf_program bpf; + if (pcap_compile(pcap.get(), &bpf, filter.c_str(), 0, PCAP_NETMASK_UNKNOWN)) { + throwException(env, "pcap_compile failed"); + return NULL; + } + + // Translate BPF program to human-readable format + const struct bpf_insn* insn = bpf.bf_insns; + for (uint32_t i = 0; i < bpf.bf_len; i++) { + bpf_string += bpf_image(insn++, i); + bpf_string += "\n"; + } + + return env->NewStringUTF(bpf_string.c_str()); +} + +static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, jstring jfilter, + jstring jpcap_filename, jbyteArray japf_program) { + ScopedUtfChars filter(env, jfilter); + ScopedUtfChars pcap_filename(env, jpcap_filename); + const uint8_t* apf_program = (uint8_t*)env->GetByteArrayElements(japf_program, NULL); + const uint32_t apf_program_len = env->GetArrayLength(japf_program); + + // Open pcap file for BPF filtering + ScopedFILE bpf_fp(fopen(pcap_filename.c_str(), "rb")); + char pcap_error[PCAP_ERRBUF_SIZE]; + ScopedPcap bpf_pcap(pcap_fopen_offline(bpf_fp.get(), pcap_error)); + if (bpf_pcap.get() == NULL) { + throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error)); + return false; + } + + // Open pcap file for APF filtering + ScopedFILE apf_fp(fopen(pcap_filename.c_str(), "rb")); + ScopedPcap apf_pcap(pcap_fopen_offline(apf_fp.get(), pcap_error)); + if (apf_pcap.get() == NULL) { + throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error)); + return false; + } + + // Compile "filter" to a BPF program + bpf_program bpf; + if (pcap_compile(bpf_pcap.get(), &bpf, filter.c_str(), 0, PCAP_NETMASK_UNKNOWN)) { + throwException(env, "pcap_compile failed"); + return false; + } + + // Install BPF filter on bpf_pcap + if (pcap_setfilter(bpf_pcap.get(), &bpf)) { + throwException(env, "pcap_setfilter failed"); + return false; + } + + while (1) { + pcap_pkthdr bpf_header, apf_header; + // Run BPF filter to the next matching packet. + const uint8_t* bpf_packet = pcap_next(bpf_pcap.get(), &bpf_header); + + // Run APF filter to the next matching packet. + const uint8_t* apf_packet; + do { + apf_packet = pcap_next(apf_pcap.get(), &apf_header); + } while (apf_packet != NULL && !accept_packet( + apf_program, apf_program_len, apf_packet, apf_header.len, 0)); + + // Make sure both filters matched the same packet. + if (apf_packet == NULL && bpf_packet == NULL) + break; + if (apf_packet == NULL || bpf_packet == NULL) + return false; + if (apf_header.len != bpf_header.len || + apf_header.ts.tv_sec != bpf_header.ts.tv_sec || + apf_header.ts.tv_usec != bpf_header.ts.tv_usec || + memcmp(apf_packet, bpf_packet, apf_header.len)) + return false; + } + return true; +} + +extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + ALOGE("ERROR: GetEnv failed"); + return -1; + } + + static JNINativeMethod gMethods[] = { + { "apfSimulate", "([B[BI)I", + (void*)com_android_server_ApfTest_apfSimulate }, + { "compileToBpf", "(Ljava/lang/String;)Ljava/lang/String;", + (void*)com_android_server_ApfTest_compileToBpf }, + { "compareBpfApf", "(Ljava/lang/String;Ljava/lang/String;[B)Z", + (void*)com_android_server_ApfTest_compareBpfApf }, + }; + + jniRegisterNativeMethods(env, "com/android/server/ApfTest", + gMethods, ARRAY_SIZE(gMethods)); + + return JNI_VERSION_1_6; +} diff --git a/services/tests/servicestests/res/raw/apf.pcap b/services/tests/servicestests/res/raw/apf.pcap Binary files differnew file mode 100644 index 000000000000..963165f19f73 --- /dev/null +++ b/services/tests/servicestests/res/raw/apf.pcap diff --git a/services/tests/servicestests/src/com/android/server/ApfTest.java b/services/tests/servicestests/src/com/android/server/ApfTest.java new file mode 100644 index 000000000000..640a6c927ed3 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/ApfTest.java @@ -0,0 +1,560 @@ +/* + * 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.server; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; + +import com.android.frameworks.servicestests.R; +import android.net.apf.ApfGenerator; +import android.net.apf.ApfGenerator.IllegalInstructionException; +import android.net.apf.ApfGenerator.Register; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; + +import libcore.io.IoUtils; +import libcore.io.Streams; + +/** + * Tests for APF program generator and interpreter. + * + * Build, install and run with: + * runtest frameworks-services -c com.android.server.ApfTest + */ +public class ApfTest extends AndroidTestCase { + @Override + public void setUp() throws Exception { + super.setUp(); + // Load up native shared library containing APF interpreter exposed via JNI. + System.loadLibrary("apfjni"); + } + + // Expected return codes from APF interpreter. + private final static int PASS = 1; + private final static int DROP = 0; + // Interpreter will just accept packets without link layer headers, so pad fake packet to at + // least the minimum packet size. + private final static int MIN_PKT_SIZE = 15; + + private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) { + assertEquals(expected, apfSimulate(program, packet, filterAge)); + } + + private void assertPass(byte[] program, byte[] packet, int filterAge) { + assertVerdict(PASS, program, packet, filterAge); + } + + private void assertDrop(byte[] program, byte[] packet, int filterAge) { + assertVerdict(DROP, program, packet, filterAge); + } + + private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge) + throws IllegalInstructionException { + assertEquals(expected, apfSimulate(gen.generate(), packet, filterAge)); + } + + private void assertPass(ApfGenerator gen, byte[] packet, int filterAge) + throws IllegalInstructionException { + assertVerdict(PASS, gen, packet, filterAge); + } + + private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge) + throws IllegalInstructionException { + assertVerdict(DROP, gen, packet, filterAge); + } + + private void assertPass(ApfGenerator gen) + throws IllegalInstructionException { + assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0); + } + + private void assertDrop(ApfGenerator gen) + throws IllegalInstructionException { + assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0); + } + + /** + * Test each instruction by generating a program containing the instruction, + * generating bytecode for that program and running it through the + * interpreter to verify it functions correctly. + */ + @LargeTest + public void testApfInstructions() throws IllegalInstructionException { + // Empty program should pass because having the program counter reach the + // location immediately after the program indicates the packet should be + // passed to the AP. + ApfGenerator gen = new ApfGenerator(); + assertPass(gen); + + // Test jumping to pass label. + gen = new ApfGenerator(); + gen.addJump(gen.PASS_LABEL); + byte[] program = gen.generate(); + assertEquals(1, program.length); + assertEquals((14 << 3) | (0 << 1) | 0, program[0]); + assertPass(program, new byte[MIN_PKT_SIZE], 0); + + // Test jumping to drop label. + gen = new ApfGenerator(); + gen.addJump(gen.DROP_LABEL); + program = gen.generate(); + assertEquals(2, program.length); + assertEquals((14 << 3) | (1 << 1) | 0, program[0]); + assertEquals(1, program[1]); + assertDrop(program, new byte[15], 15); + + // Test jumping if equal to 0. + gen = new ApfGenerator(); + gen.addJumpIfR0Equals(0, gen.DROP_LABEL); + assertDrop(gen); + + // Test jumping if not equal to 0. + gen = new ApfGenerator(); + gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL); + assertPass(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1); + gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL); + assertDrop(gen); + + // Test jumping if registers equal. + gen = new ApfGenerator(); + gen.addJumpIfR0EqualsR1(gen.DROP_LABEL); + assertDrop(gen); + + // Test jumping if registers not equal. + gen = new ApfGenerator(); + gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL); + assertPass(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1); + gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL); + assertDrop(gen); + + // Test load immediate. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test add. + gen = new ApfGenerator(); + gen.addAdd(1234567890); + gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test subtract. + gen = new ApfGenerator(); + gen.addAdd(-1234567890); + gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test or. + gen = new ApfGenerator(); + gen.addOr(1234567890); + gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test and. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addAnd(123456789); + gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL); + assertDrop(gen); + + // Test left shift. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addLeftShift(1); + gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL); + assertDrop(gen); + + // Test right shift. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addRightShift(1); + gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL); + assertDrop(gen); + + // Test multiply. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addMul(2); + gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL); + assertDrop(gen); + + // Test divide. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addDiv(2); + gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL); + assertDrop(gen); + + // Test divide by zero. + gen = new ApfGenerator(); + gen.addDiv(0); + gen.addJump(gen.DROP_LABEL); + assertPass(gen); + + // Test add. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 1234567890); + gen.addAddR1(); + gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test subtract. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, -1234567890); + gen.addAddR1(); + gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test or. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 1234567890); + gen.addOrR1(); + gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test and. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addLoadImmediate(Register.R1, 123456789); + gen.addAndR1(); + gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL); + assertDrop(gen); + + // Test left shift. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addLoadImmediate(Register.R1, 1); + gen.addLeftShiftR1(); + gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL); + assertDrop(gen); + + // Test right shift. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addLoadImmediate(Register.R1, -1); + gen.addLeftShiftR1(); + gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL); + assertDrop(gen); + + // Test multiply. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addLoadImmediate(Register.R1, 2); + gen.addMulR1(); + gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL); + assertDrop(gen); + + // Test divide. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addLoadImmediate(Register.R1, 2); + gen.addDivR1(); + gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL); + assertDrop(gen); + + // Test divide by zero. + gen = new ApfGenerator(); + gen.addDivR1(); + gen.addJump(gen.DROP_LABEL); + assertPass(gen); + + // Test byte load. + gen = new ApfGenerator(); + gen.addLoad8(Register.R0, 1); + gen.addJumpIfR0Equals(45, gen.DROP_LABEL); + assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); + + // Test out of bounds load. + gen = new ApfGenerator(); + gen.addLoad8(Register.R0, 16); + gen.addJumpIfR0Equals(0, gen.DROP_LABEL); + assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); + + // Test half-word load. + gen = new ApfGenerator(); + gen.addLoad16(Register.R0, 1); + gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL); + assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0); + + // Test word load. + gen = new ApfGenerator(); + gen.addLoad32(Register.R0, 1); + gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL); + assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0); + + // Test byte indexed load. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 1); + gen.addLoad8Indexed(Register.R0, 0); + gen.addJumpIfR0Equals(45, gen.DROP_LABEL); + assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); + + // Test out of bounds indexed load. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 8); + gen.addLoad8Indexed(Register.R0, 8); + gen.addJumpIfR0Equals(0, gen.DROP_LABEL); + assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); + + // Test half-word indexed load. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 1); + gen.addLoad16Indexed(Register.R0, 0); + gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL); + assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0); + + // Test word indexed load. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 1); + gen.addLoad32Indexed(Register.R0, 0); + gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL); + assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0); + + // Test jumping if greater than. + gen = new ApfGenerator(); + gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL); + assertPass(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1); + gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL); + assertDrop(gen); + + // Test jumping if less than. + gen = new ApfGenerator(); + gen.addJumpIfR0LessThan(0, gen.DROP_LABEL); + assertPass(gen); + gen = new ApfGenerator(); + gen.addJumpIfR0LessThan(1, gen.DROP_LABEL); + assertDrop(gen); + + // Test jumping if any bits set. + gen = new ApfGenerator(); + gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); + assertPass(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1); + gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); + assertDrop(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 3); + gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); + assertDrop(gen); + + // Test jumping if register greater than. + gen = new ApfGenerator(); + gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL); + assertPass(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 2); + gen.addLoadImmediate(Register.R1, 1); + gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL); + assertDrop(gen); + + // Test jumping if register less than. + gen = new ApfGenerator(); + gen.addJumpIfR0LessThanR1(gen.DROP_LABEL); + assertPass(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 1); + gen.addJumpIfR0LessThanR1(gen.DROP_LABEL); + assertDrop(gen); + + // Test jumping if any bits set in register. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 3); + gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); + assertPass(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 3); + gen.addLoadImmediate(Register.R0, 1); + gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); + assertDrop(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 3); + gen.addLoadImmediate(Register.R0, 3); + gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); + assertDrop(gen); + + // Test load from memory. + gen = new ApfGenerator(); + gen.addLoadFromMemory(Register.R0, 0); + gen.addJumpIfR0Equals(0, gen.DROP_LABEL); + assertDrop(gen); + + // Test store to memory. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 1234567890); + gen.addStoreToMemory(Register.R1, 12); + gen.addLoadFromMemory(Register.R0, 12); + gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test filter age pre-filled memory. + gen = new ApfGenerator(); + gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT); + gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); + assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890); + + // Test packet size pre-filled memory. + gen = new ApfGenerator(); + gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT); + gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL); + assertDrop(gen); + + // Test IPv4 header size pre-filled memory. + gen = new ApfGenerator(); + gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); + gen.addJumpIfR0Equals(20, gen.DROP_LABEL); + assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0); + + // Test not. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addNot(Register.R0); + gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test negate. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addNeg(Register.R0); + gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test move. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 1234567890); + gen.addMove(Register.R0); + gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); + assertDrop(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addMove(Register.R1); + gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); + assertDrop(gen); + + // Test swap. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R1, 1234567890); + gen.addSwap(); + gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); + assertDrop(gen); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1234567890); + gen.addSwap(); + gen.addJumpIfR0Equals(0, gen.DROP_LABEL); + assertDrop(gen); + + // Test jump if bytes not equal. + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1); + gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); + program = gen.generate(); + assertEquals(6, program.length); + assertEquals((13 << 3) | (1 << 1) | 0, program[0]); + assertEquals(1, program[1]); + assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]); + assertEquals(1, program[3]); + assertEquals(1, program[4]); + assertEquals(123, program[5]); + assertDrop(program, new byte[MIN_PKT_SIZE], 0); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1); + gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); + byte[] packet123 = new byte[]{0,123,0,0,0,0,0,0,0,0,0,0,0,0,0}; + assertPass(gen, packet123, 0); + gen = new ApfGenerator(); + gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); + assertDrop(gen, packet123, 0); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1); + gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL); + byte[] packet12345 = new byte[]{0,1,2,3,4,5,0,0,0,0,0,0,0,0,0}; + assertDrop(gen, packet12345, 0); + gen = new ApfGenerator(); + gen.addLoadImmediate(Register.R0, 1); + gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL); + assertPass(gen, packet12345, 0); + } + + /** + * Generate some BPF programs, translate them to APF, then run APF and BPF programs + * over packet traces and verify both programs filter out the same packets. + */ + @LargeTest + public void testApfAgainstBpf() throws Exception { + String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53", + "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24", + "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000", + "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" }; + String pcap_filename = stageFile(R.raw.apf); + for (String tcpdump_filter : tcpdump_filters) { + byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter)); + assertTrue("Failed to match for filter: " + tcpdump_filter, + compareBpfApf(tcpdump_filter, pcap_filename, apf_program)); + } + } + + /** + * Stage a file for testing, i.e. make it native accessible. Given a resource ID, + * copy that resource into the app's data directory and return the path to it. + */ + private String stageFile(int rawId) throws Exception { + File file = new File(getContext().getFilesDir(), "staged_file"); + new File(file.getParent()).mkdirs(); + InputStream in = null; + OutputStream out = null; + try { + in = getContext().getResources().openRawResource(rawId); + out = new FileOutputStream(file); + Streams.copy(in, out); + } finally { + if (in != null) in.close(); + if (out != null) out.close(); + } + return file.getAbsolutePath(); + } + + /** + * Call the APF interpreter the run {@code program} on {@code packet} pretending the + * filter was installed {@code filter_age} seconds ago. + */ + private native static int apfSimulate(byte[] program, byte[] packet, int filter_age); + + /** + * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF + * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d". + */ + private native static String compileToBpf(String filter); + + /** + * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump + * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and + * at the same time using APF program {@code apf_program}. Return {@code true} if + * both APF and BPF programs filter out exactly the same packets. + */ + private native static boolean compareBpfApf(String filter, String pcap_filename, + byte[] apf_program); +} diff --git a/services/tests/servicestests/src/com/android/server/Bpf2Apf.java b/services/tests/servicestests/src/com/android/server/Bpf2Apf.java new file mode 100644 index 000000000000..29594a84fc48 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/Bpf2Apf.java @@ -0,0 +1,327 @@ +/* + * 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; + +import android.net.apf.ApfGenerator; +import android.net.apf.ApfGenerator.IllegalInstructionException; +import android.net.apf.ApfGenerator.Register; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +/** + * BPF to APF translator. + * + * Note: This is for testing purposes only and is not guaranteed to support + * translation of all BPF programs. + * + * Example usage: + * javac net/java/android/net/apf/ApfGenerator.java \ + * tests/servicestests/src/com/android/server/Bpf2Apf.java + * sudo tcpdump -i em1 -d icmp | java -classpath tests/servicestests/src:net/java \ + * com.android.server.Bpf2Apf + */ +public class Bpf2Apf { + private static int parseImm(String line, String arg) { + if (!arg.startsWith("#0x")) { + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + final long val_long = Long.parseLong(arg.substring(3), 16); + if (val_long < 0 || val_long > Long.parseLong("ffffffff", 16)) { + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + return new Long((val_long << 32) >> 32).intValue(); + } + + /** + * Convert a single line of "tcpdump -d" (human readable BPF program dump) {@code line} into + * APF instruction(s) and append them to {@code gen}. Here's an example line: + * (001) jeq #0x86dd jt 2 jf 7 + */ + private static void convertLine(String line, ApfGenerator gen) + throws IllegalInstructionException { + if (line.indexOf("(") != 0 || line.indexOf(")") != 4 || line.indexOf(" ") != 5) { + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + int label = Integer.parseInt(line.substring(1, 4)); + gen.defineLabel(Integer.toString(label)); + String opcode = line.substring(6, 10).trim(); + String arg = line.substring(15, Math.min(32, line.length())).trim(); + switch (opcode) { + case "ld": + case "ldh": + case "ldb": + case "ldx": + case "ldxb": + case "ldxh": + Register dest = opcode.contains("x") ? Register.R1 : Register.R0; + if (arg.equals("4*([14]&0xf)")) { + if (!opcode.equals("ldxb")) { + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + gen.addLoadFromMemory(dest, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); + break; + } + if (arg.equals("#pktlen")) { + if (!opcode.equals("ld")) { + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + gen.addLoadFromMemory(dest, gen.PACKET_SIZE_MEMORY_SLOT); + break; + } + if (arg.startsWith("#0x")) { + if (!opcode.equals("ld")) { + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + gen.addLoadImmediate(dest, parseImm(line, arg)); + break; + } + if (arg.startsWith("M[")) { + if (!opcode.startsWith("ld")) { + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + int memory_slot = Integer.parseInt(arg.substring(2, arg.length() - 1)); + if (memory_slot < 0 || memory_slot >= gen.MEMORY_SLOTS || + // Disallow use of pre-filled slots as BPF programs might + // wrongfully assume they're initialized to 0. + (memory_slot >= gen.FIRST_PREFILLED_MEMORY_SLOT && + memory_slot <= gen.LAST_PREFILLED_MEMORY_SLOT)) { + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + gen.addLoadFromMemory(dest, memory_slot); + break; + } + if (arg.startsWith("[x + ")) { + int offset = Integer.parseInt(arg.substring(5, arg.length() - 1)); + switch (opcode) { + case "ld": + case "ldx": + gen.addLoad32Indexed(dest, offset); + break; + case "ldh": + case "ldxh": + gen.addLoad16Indexed(dest, offset); + break; + case "ldb": + case "ldxb": + gen.addLoad8Indexed(dest, offset); + break; + } + } else { + int offset = Integer.parseInt(arg.substring(1, arg.length() - 1)); + switch (opcode) { + case "ld": + case "ldx": + gen.addLoad32(dest, offset); + break; + case "ldh": + case "ldxh": + gen.addLoad16(dest, offset); + break; + case "ldb": + case "ldxb": + gen.addLoad8(dest, offset); + break; + } + } + break; + case "st": + case "stx": + Register src = opcode.contains("x") ? Register.R1 : Register.R0; + if (!arg.startsWith("M[")) { + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + int memory_slot = Integer.parseInt(arg.substring(2, arg.length() - 1)); + if (memory_slot < 0 || memory_slot >= gen.MEMORY_SLOTS || + // Disallow overwriting pre-filled slots + (memory_slot >= gen.FIRST_PREFILLED_MEMORY_SLOT && + memory_slot <= gen.LAST_PREFILLED_MEMORY_SLOT)) { + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + gen.addStoreToMemory(src, memory_slot); + break; + case "add": + case "and": + case "or": + case "sub": + if (arg.equals("x")) { + switch(opcode) { + case "add": + gen.addAddR1(); + break; + case "and": + gen.addAndR1(); + break; + case "or": + gen.addOrR1(); + break; + case "sub": + gen.addNeg(Register.R1); + gen.addAddR1(); + gen.addNeg(Register.R1); + break; + } + } else { + int imm = parseImm(line, arg); + switch(opcode) { + case "add": + gen.addAdd(imm); + break; + case "and": + gen.addAnd(imm); + break; + case "or": + gen.addOr(imm); + break; + case "sub": + gen.addAdd(-imm); + break; + } + } + break; + case "jeq": + case "jset": + case "jgt": + case "jge": + int val = 0; + boolean reg_compare; + if (arg.startsWith("x")) { + reg_compare = true; + } else { + reg_compare = false; + val = parseImm(line, arg); + } + int jt_offset = line.indexOf("jt"); + int jf_offset = line.indexOf("jf"); + String true_label = line.substring(jt_offset + 2, jf_offset).trim(); + String false_label = line.substring(jf_offset + 2).trim(); + boolean true_label_is_fallthrough = Integer.parseInt(true_label) == label + 1; + boolean false_label_is_fallthrough = Integer.parseInt(false_label) == label + 1; + if (true_label_is_fallthrough && false_label_is_fallthrough) + break; + switch (opcode) { + case "jeq": + if (!true_label_is_fallthrough) { + if (reg_compare) { + gen.addJumpIfR0EqualsR1(true_label); + } else { + gen.addJumpIfR0Equals(val, true_label); + } + } + if (!false_label_is_fallthrough) { + if (!true_label_is_fallthrough) { + gen.addJump(false_label); + } else if (reg_compare) { + gen.addJumpIfR0NotEqualsR1(false_label); + } else { + gen.addJumpIfR0NotEquals(val, false_label); + } + } + break; + case "jset": + if (reg_compare) { + gen.addJumpIfR0AnyBitsSetR1(true_label); + } else { + gen.addJumpIfR0AnyBitsSet(val, true_label); + } + if (!false_label_is_fallthrough) { + gen.addJump(false_label); + } + break; + case "jgt": + if (!true_label_is_fallthrough || + // We have no less-than-or-equal-to register to register + // comparison instruction, so in this case we'll jump + // around an unconditional jump. + (!false_label_is_fallthrough && reg_compare)) { + if (reg_compare) { + gen.addJumpIfR0GreaterThanR1(true_label); + } else { + gen.addJumpIfR0GreaterThan(val, true_label); + } + } + if (!false_label_is_fallthrough) { + if (!true_label_is_fallthrough || reg_compare) { + gen.addJump(false_label); + } else { + gen.addJumpIfR0LessThan(val + 1, false_label); + } + } + break; + case "jge": + if (!false_label_is_fallthrough || + // We have no greater-than-or-equal-to register to register + // comparison instruction, so in this case we'll jump + // around an unconditional jump. + (!true_label_is_fallthrough && reg_compare)) { + if (reg_compare) { + gen.addJumpIfR0LessThanR1(false_label); + } else { + gen.addJumpIfR0LessThan(val, false_label); + } + } + if (!true_label_is_fallthrough) { + if (!false_label_is_fallthrough || reg_compare) { + gen.addJump(true_label); + } else { + gen.addJumpIfR0GreaterThan(val - 1, true_label); + } + } + break; + } + break; + case "ret": + if (arg.equals("#0")) { + gen.addJump(gen.DROP_LABEL); + } else { + gen.addJump(gen.PASS_LABEL); + } + break; + case "tax": + gen.addMove(Register.R1); + break; + case "txa": + gen.addMove(Register.R0); + break; + default: + throw new IllegalArgumentException("Unhandled instruction: " + line); + } + } + + /** + * Convert the output of "tcpdump -d" (human readable BPF program dump) {@code bpf} into an APF + * program and return it. + */ + public static byte[] convert(String bpf) throws IllegalInstructionException { + ApfGenerator gen = new ApfGenerator(); + for (String line : bpf.split("\\n")) convertLine(line, gen); + return gen.generate(); + } + + /** + * Convert the output of "tcpdump -d" (human readable BPF program dump) piped in stdin into an + * APF program and output it via stdout. + */ + public static void main(String[] args) throws Exception { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + String line = null; + StringBuilder responseData = new StringBuilder(); + ApfGenerator gen = new ApfGenerator(); + while ((line = in.readLine()) != null) convertLine(line, gen); + System.out.write(gen.generate()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index 3dc1a9ab7847..53ca45dde5ae 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -29,6 +29,7 @@ import android.test.AndroidTestCase; import java.io.File; import java.util.List; +import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; @@ -135,8 +136,7 @@ public abstract class DpmTestBase extends AndroidTestCase { doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceiversAsUser( MockUtils.checkIntentComponent(admin), - eq(PackageManager.GET_META_DATA - | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + anyInt(), eq(UserHandle.getUserId(packageUid))); // Set up getPackageInfo(). diff --git a/services/usb/java/com/android/server/usb/MtpNotificationManager.java b/services/usb/java/com/android/server/usb/MtpNotificationManager.java index 203d35ed1fc4..17039bb6870c 100644 --- a/services/usb/java/com/android/server/usb/MtpNotificationManager.java +++ b/services/usb/java/com/android/server/usb/MtpNotificationManager.java @@ -30,7 +30,6 @@ import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; import android.os.UserHandle; -import android.util.Log; /** * Manager for MTP storage notification. diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 72ff27227efb..c122c5a365fc 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -1414,6 +1414,23 @@ public class TelecomManager { return result; } + /** + * Launches the {@link android.app.Activity} to manage blocked numbers. + * <p> This method displays the UI to manage blocked numbers only if + * {@link android.provider.BlockedNumberContract#canCurrentUserBlockNumbers(Context)} returns + * {@code true} for the current user. + */ + public void launchManageBlockedNumbersActivity() { + ITelecomService service = getTelecomService(); + if (service != null) { + try { + service.launchManageBlockedNumbersActivity(mContext.getPackageName()); + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelecomService#manageBlockedNumbers", e); + } + } + } + private ITelecomService getTelecomService() { if (mTelecomServiceOverride != null) { return mTelecomServiceOverride; diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index d1d6e0dcdece..6229ed921bcc 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -25,6 +25,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.Typeface; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.DisplayMetrics; @@ -338,7 +339,7 @@ public class SubscriptionInfo implements Parcelable { public static String givePrintableIccid(String iccId) { String iccIdToPrint = null; if (iccId != null) { - if (iccId.length() > 9) { + if (iccId.length() > 9 && !Build.IS_DEBUGGABLE) { iccIdToPrint = iccId.substring(0, 9) + "XXXXXXXXXXX"; } else { iccIdToPrint = iccId; diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index b028ce61f821..de7b9c268c99 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -356,6 +356,15 @@ </activity> <activity + android:name="MovingSurfaceViewActivity" + android:label="SurfaceView/Animated Movement"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity android:name="GLTextureViewActivity" android:label="TextureView/OpenGL"> <intent-filter> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java new file mode 100644 index 000000000000..cd15ef156a5c --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java @@ -0,0 +1,125 @@ +/* + * 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.test.hwui; + +import android.animation.ObjectAnimator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.os.Bundle; +import android.util.Log; +import android.view.Gravity; +import android.view.SurfaceHolder; +import android.view.SurfaceHolder.Callback; +import android.view.SurfaceView; +import android.view.View; +import android.view.animation.LinearInterpolator; +import android.widget.FrameLayout; + +public class MovingSurfaceViewActivity extends Activity implements Callback { + static final String TAG = "MovingSurfaceView"; + SurfaceView mSurfaceView; + ObjectAnimator mAnimator; + + class MySurfaceView extends SurfaceView { + boolean mSlowToggled; + + public MySurfaceView(Context context) { + super(context); + setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mSlowToggled = !mSlowToggled; + Log.d(TAG, "SLOW MODE: " + mSlowToggled); + invalidate(); + } + }); + setWillNotDraw(false); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + if (mSlowToggled) { + try { + Thread.sleep(16); + } catch (InterruptedException e) {} + } + } + + public void setMyTranslationY(float ty) { + setTranslationY(ty); + if (mSlowToggled) { + invalidate(); + } + } + + public float getMyTranslationY() { + return getTranslationY(); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + FrameLayout content = new FrameLayout(this); + + mSurfaceView = new MySurfaceView(this); + mSurfaceView.getHolder().addCallback(this); + + final float density = getResources().getDisplayMetrics().density; + int size = (int) (200 * density); + + content.addView(mSurfaceView, new FrameLayout.LayoutParams( + size, size, Gravity.CENTER)); + mAnimator = ObjectAnimator.ofFloat(mSurfaceView, "myTranslationY", + 0, size); + mAnimator.setRepeatMode(ObjectAnimator.REVERSE); + mAnimator.setRepeatCount(ObjectAnimator.INFINITE); + mAnimator.setDuration(200); + mAnimator.setInterpolator(new LinearInterpolator()); + setContentView(content); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + Canvas canvas = holder.lockCanvas(); + canvas.drawARGB(0xFF, 0x00, 0xFF, 0x00); + holder.unlockCanvasAndPost(canvas); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + } + + @Override + protected void onResume() { + super.onResume(); + mAnimator.start(); + } + + @Override + protected void onPause() { + mAnimator.pause(); + super.onPause(); + } +} diff --git a/wifi/java/android/net/wifi/AnqpInformationElement.java b/wifi/java/android/net/wifi/AnqpInformationElement.java new file mode 100644 index 000000000000..47b712991c49 --- /dev/null +++ b/wifi/java/android/net/wifi/AnqpInformationElement.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +/** + * This object contains the payload of an ANQP element. + * Vendor id is the vendor ID for the element, or 0 if it is an 802.11(u) element. + * Hotspot 2.0 uses the WFA Vendor ID which is 0x506f9a + * The payload contains the bytes of the payload, starting after the length octet(s). + * @hide + */ +public class AnqpInformationElement { + public static final int HOTSPOT20_VENDOR_ID = 0x506f9a; + + public static final int ANQP_QUERY_LIST = 256; + public static final int ANQP_CAPABILITY_LIST = 257; + public static final int ANQP_VENUE_NAME = 258; + public static final int ANQP_EMERGENCY_NUMBER = 259; + public static final int ANQP_NWK_AUTH_TYPE = 260; + public static final int ANQP_ROAMING_CONSORTIUM = 261; + public static final int ANQP_IP_ADDR_AVAILABILITY = 262; + public static final int ANQP_NAI_REALM = 263; + public static final int ANQP_3GPP_NETWORK = 264; + public static final int ANQP_GEO_LOC = 265; + public static final int ANQP_CIVIC_LOC = 266; + public static final int ANQP_LOC_URI = 267; + public static final int ANQP_DOM_NAME = 268; + public static final int ANQP_EMERGENCY_ALERT = 269; + public static final int ANQP_TDLS_CAP = 270; + public static final int ANQP_EMERGENCY_NAI = 271; + public static final int ANQP_NEIGHBOR_REPORT = 272; + public static final int ANQP_VENDOR_SPEC = 56797; + + public static final int HS_QUERY_LIST = 1; + public static final int HS_CAPABILITY_LIST = 2; + public static final int HS_FRIENDLY_NAME = 3; + public static final int HS_WAN_METRICS = 4; + public static final int HS_CONN_CAPABILITY = 5; + public static final int HS_NAI_HOME_REALM_QUERY = 6; + public static final int HS_OPERATING_CLASS = 7; + public static final int HS_OSU_PROVIDERS = 8; + public static final int HS_ICON_REQUEST = 10; + public static final int HS_ICON_FILE = 11; + + private final int mVendorId; + private final int mElementId; + private final byte[] mPayload; + + public AnqpInformationElement(int vendorId, int elementId, byte[] payload) { + mVendorId = vendorId; + mElementId = elementId; + mPayload = payload; + } + + public int getVendorId() { + return mVendorId; + } + + public int getElementId() { + return mElementId; + } + + public byte[] getPayload() { + return mPayload; + } +} diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index bad4e9cf0397..1c7a308746b0 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -20,7 +20,7 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.ScanSettings; import android.net.wifi.ScanResult; -import android.net.wifi.ScanInfo; +import android.net.wifi.PasspointManagementObjectDefinition; import android.net.wifi.WifiConnectionStatistics; import android.net.wifi.WifiActivityEnergyInfo; import android.net.Network; @@ -50,6 +50,17 @@ interface IWifiManager int addOrUpdateNetwork(in WifiConfiguration config); + int addPasspointManagementObject(String mo); + + int modifyPasspointManagementObject(String fqdn, + in List<PasspointManagementObjectDefinition> mos); + + void queryPasspointIcon(long bssid, String fileName); + + int matchProviderWithCurrentNetwork(String fqdn); + + void deauthenticateNetwork(long holdoff, boolean ess); + boolean removeNetwork(int netId); boolean enableNetwork(int netId, boolean disableOthers); @@ -64,10 +75,6 @@ interface IWifiManager void disconnect(); - List<ScanInfo> getScanInfos(String callingPackage); - - void setOsuSelection(int osuID); - void reconnect(); void reassociate(); diff --git a/wifi/java/android/net/wifi/ScanInfo.aidl b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl index 18ae5088146f..eb7cc39d5e33 100644 --- a/wifi/java/android/net/wifi/ScanInfo.aidl +++ b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015, The Android Open Source Project + * Copyright (c) 2008, 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. @@ -16,4 +16,4 @@ package android.net.wifi; -parcelable ScanInfo; +parcelable PasspointManagementObjectDefinition; diff --git a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java new file mode 100644 index 000000000000..611ed15c76b5 --- /dev/null +++ b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This object describes a partial tree structure in the Hotspot 2.0 release 2 management object. + * The object is used during subscription remediation to modify parts of an existing PPS MO + * tree (Hotspot 2.0 specification section 9.1). + * @hide + */ +public class PasspointManagementObjectDefinition implements Parcelable { + private final String mBaseUri; + private final String mUrn; + private final String mMoTree; + + public PasspointManagementObjectDefinition(String baseUri, String urn, String moTree) { + mBaseUri = baseUri; + mUrn = urn; + mMoTree = moTree; + } + + public String getmBaseUri() { + return mBaseUri; + } + + public String getmUrn() { + return mUrn; + } + + public String getmMoTree() { + return mMoTree; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mBaseUri); + dest.writeString(mUrn); + dest.writeString(mMoTree); + } + + /** + * Implement the Parcelable interface {@hide} + */ + public static final Creator<PasspointManagementObjectDefinition> CREATOR = + new Creator<PasspointManagementObjectDefinition>() { + public PasspointManagementObjectDefinition createFromParcel(Parcel in) { + return new PasspointManagementObjectDefinition( + in.readString(), /* base URI */ + in.readString(), /* URN */ + in.readString() /* Tree XML */ + ); + } + + public PasspointManagementObjectDefinition[] newArray(int size) { + return new PasspointManagementObjectDefinition[size]; + } + }; +} + diff --git a/wifi/java/android/net/wifi/ScanInfo.java b/wifi/java/android/net/wifi/ScanInfo.java deleted file mode 100644 index 39186fa7a38a..000000000000 --- a/wifi/java/android/net/wifi/ScanInfo.java +++ /dev/null @@ -1,189 +0,0 @@ -package android.net.wifi; - -import android.os.Parcel; -import android.os.Parcelable; - -public class ScanInfo implements Parcelable { - private final ScanResult mScanResult; - - private final long mBSSID; // The BSSID of the best AP with an SSID matching the OSU - private final int mRSSI; // RSSI of the AP with BSSID - private final String mSSID; // The SSID to connect to for an OSU connection. - private final String mName; - private final String mServiceDescription; - private final String mIconType; - private final byte[] mIconData; - private final int mOSUIdentity; - - public ScanInfo(ScanResult scanResult) { - mScanResult = scanResult; - - mBSSID = -1; - mRSSI = -1; - mSSID = null; - mName = null; - mServiceDescription = null; - mIconType = null; - mIconData = null; - mOSUIdentity = -1; - } - - public ScanInfo(long BSSID, int rssi, String SSID, String name, String serviceDescription, - String iconType, byte[] iconData, int OSUIdentity) { - mBSSID = BSSID; - mRSSI = rssi; - mSSID = SSID; - mName = name; - mServiceDescription = serviceDescription; - mIconType = iconType; - mIconData = iconData; - mOSUIdentity = OSUIdentity; - - mScanResult = null; - } - - /** - * Get the scan result of this ScanInfo. - * @return The ScanResult, if this ScanInfo contains a one. If the ScanInfo contains - * OSU information getScanResult will return null. - */ - public ScanResult getScanResult() { - return mScanResult; - } - - /** - * OSU only: The BSSID of the AP who advertises the OSU SSID. This value is not guaranteed to - * be correct; In the somewhat unlikely case that multiple APs advertise OSU SSIDs that matches - * an OSU information element returned through ANQP and one of those is not related to an OSU - * there is a (slight) risk that the BSSID is for a "spoof" OSU. - * The matching algorithm that produces the ScanInfo objects makes a best effort to get the - * matching right though and since it is (a) fair to assume that the OSU SSID resides on the - * same AP as the one advertising the OSU information, and (b) BSSIDs for multi-SSID APs are - * typically adjacent to each other, matching will prefer the BSSID closest to the advertising - * APs BSSID if multiple SSIDs match. - * @return The BSSID. - */ - public long getBssid() { - return mBSSID; - } - - /** - * OSU only. - * @return The signal level of the AP associated with the BSSID from getBSSID. - */ - public int getRssi() { - return mRSSI; - } - - /** - * OSU only. - * @return The SSID of the AP to which to associate to establish an OSU connection. - */ - public String getSsid() { - return mSSID; - } - - /** - * OSU only. - * @return The name of the Service Provider of the OSU. - */ - public String getName() { - return mName; - } - - /** - * OSU only. - * @return The service description of the OSU. - */ - public String getServiceDescription() { - return mServiceDescription; - } - - /** - * OSU only. - * Get the type of icon that icon data represents, e.g. JPG, PNG etc. This field is formatted - * using standard MIME encodings per RFC-4288 and IANA MIME media types. - * @return The icon type in icon data. - */ - public String getIconType() { - return mIconType; - } - - /** - * OSU only. - * @return The binary data of the icon. - */ - public byte[] getIconData() { - return mIconData; - } - - /** - * OSU only. - * @return a unique identity for the OSU. This value is generated by the framework and should - * be used to uniquely identify a specific OSU. Please note that values may be reused after - * a very long time-span (in any normal scenario, likely years) and implementations should make - * sure to not rely on any long term persisted values. - */ - public int getOsuIdentity() { - return mOSUIdentity; - } - - private static final int ScanResultMarker = 0; - private static final int OSUMarker = 1; - - @Override - public int describeContents() { - return 0; - } - - /** Implement the Parcelable interface {@hide} */ - public static final Creator<ScanInfo> CREATOR = - new Creator<ScanInfo>() { - @Override - public ScanInfo createFromParcel(Parcel source) { - int marker = source.readInt(); - if (marker == ScanResultMarker) { - return new ScanInfo(ScanResult.CREATOR.createFromParcel(source)); - } - else if (marker == OSUMarker) { - return new ScanInfo( - source.readLong(), - source.readInt(), - source.readString(), - source.readString(), - source.readString(), - source.readString(), - source.createByteArray(), - source.readInt() - ); - } - else { - throw new RuntimeException("Bad ScanInfo data"); - } - } - - @Override - public ScanInfo[] newArray(int size) { - return new ScanInfo[0]; - } - }; - - @Override - public void writeToParcel(Parcel dest, int flags) { - if (mScanResult != null) { - dest.writeInt(ScanResultMarker); - mScanResult.writeToParcel(dest, flags); - return; - } - - dest.writeInt(OSUMarker); - dest.writeLong(mBSSID); - dest.writeInt(mRSSI); - dest.writeString(mSSID); - dest.writeString(mName); - dest.writeString(mServiceDescription); - dest.writeString(mIconType); - dest.writeByteArray(mIconData); - dest.writeInt(mOSUIdentity); - } -} diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index 1f0533959e01..4a86c59542ab 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -43,6 +43,19 @@ public class ScanResult implements Parcelable { * The address of the access point. */ public String BSSID; + + /** + * The HESSID from the beacon. + * @hide + */ + public long hessid; + + /** + * The ANQP Domain ID from the Hotspot 2.0 Indication element, if present. + * @hide + */ + public int anqpDomainId; + /** * Describes the authentication, key management, and encryption schemes * supported by the access point. @@ -341,14 +354,27 @@ public class ScanResult implements Parcelable { /** information elements found in the beacon * @hide */ - public InformationElement informationElements[]; + public InformationElement[] informationElements; + + /** ANQP response elements. + * @hide + */ + public AnqpInformationElement[] anqpElements; /** {@hide} */ - public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, - long tsf) { + public ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId, + byte[] osuProviders, String caps, int level, int frequency, long tsf) { this.wifiSsid = wifiSsid; this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; this.BSSID = BSSID; + this.hessid = hessid; + this.anqpDomainId = anqpDomainId; + if (osuProviders != null) { + this.anqpElements = new AnqpInformationElement[1]; + this.anqpElements[0] = + new AnqpInformationElement(AnqpInformationElement.HOTSPOT20_VENDOR_ID, + AnqpInformationElement.HS_OSU_PROVIDERS, osuProviders); + } this.capabilities = caps; this.level = level; this.frequency = frequency; @@ -380,11 +406,14 @@ public class ScanResult implements Parcelable { } /** {@hide} */ - public ScanResult(String Ssid, String BSSID, String caps, int level, int frequency, + public ScanResult(String Ssid, String BSSID, long hessid, int anqpDomainId, String caps, + int level, int frequency, long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) { this.SSID = Ssid; this.BSSID = BSSID; + this.hessid = hessid; + this.anqpDomainId = anqpDomainId; this.capabilities = caps; this.level = level; this.frequency = frequency; @@ -402,11 +431,12 @@ public class ScanResult implements Parcelable { } /** {@hide} */ - public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, String caps, int level, + public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, long hessid, int anqpDomainId, + String caps, int level, int frequency, long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) { - this(Ssid, BSSID, caps,level, frequency, tsf, distCm, distSdCm, channelWidth, centerFreq0, - centerFreq1, is80211McRTTResponder); + this(Ssid, BSSID, hessid, anqpDomainId, caps, level, frequency, tsf, distCm, + distSdCm, channelWidth, centerFreq0, centerFreq1, is80211McRTTResponder); this.wifiSsid = wifiSsid; } @@ -416,6 +446,10 @@ public class ScanResult implements Parcelable { wifiSsid = source.wifiSsid; SSID = source.SSID; BSSID = source.BSSID; + hessid = source.hessid; + anqpDomainId = source.anqpDomainId; + informationElements = source.informationElements; + anqpElements = source.anqpElements; capabilities = source.capabilities; level = source.level; frequency = source.frequency; @@ -496,6 +530,8 @@ public class ScanResult implements Parcelable { } dest.writeString(SSID); dest.writeString(BSSID); + dest.writeLong(hessid); + dest.writeInt(anqpDomainId); dest.writeString(capabilities); dest.writeInt(level); dest.writeInt(frequency); @@ -532,6 +568,18 @@ public class ScanResult implements Parcelable { for (int i = 0; i < anqpLines.size(); i++) { dest.writeString(anqpLines.get(i)); } + } + else { + dest.writeInt(0); + } + if (anqpElements != null) { + dest.writeInt(anqpElements.length); + for (AnqpInformationElement element : anqpElements) { + dest.writeInt(element.getVendorId()); + dest.writeInt(element.getElementId()); + dest.writeInt(element.getPayload().length); + dest.writeByteArray(element.getPayload()); + } } else { dest.writeInt(0); } @@ -546,19 +594,22 @@ public class ScanResult implements Parcelable { wifiSsid = WifiSsid.CREATOR.createFromParcel(in); } ScanResult sr = new ScanResult( - wifiSsid, - in.readString(), /* SSID */ - in.readString(), /* BSSID */ - in.readString(), /* capabilities */ - in.readInt(), /* level */ - in.readInt(), /* frequency */ - in.readLong(), /* timestamp */ - in.readInt(), /* distanceCm */ - in.readInt(), /* distanceSdCm */ - in.readInt(), /* channelWidth */ - in.readInt(), /* centerFreq0 */ - in.readInt(), /* centerFreq1 */ - false /* rtt responder, fixed with flags below */ + wifiSsid, + in.readString(), /* SSID */ + in.readString(), /* BSSID */ + in.readLong(), /* HESSID */ + in.readInt(), /* ANQP Domain ID */ + in.readString(), /* capabilities */ + in.readInt(), /* level */ + in.readInt(), /* frequency */ + in.readLong(), /* timestamp */ + in.readInt(), /* distanceCm */ + in.readInt(), /* distanceSdCm */ + in.readInt(), /* channelWidth */ + in.readInt(), /* centerFreq0 */ + in.readInt(), /* centerFreq1 */ + false /* rtt responder, + fixed with flags below */ ); sr.seen = in.readLong(); @@ -590,6 +641,19 @@ public class ScanResult implements Parcelable { sr.anqpLines.add(in.readString()); } } + n = in.readInt(); + if (n != 0) { + sr.anqpElements = new AnqpInformationElement[n]; + for (int i = 0; i < n; i++) { + int vendorId = in.readInt(); + int elementId = in.readInt(); + int len = in.readInt(); + byte[] payload = new byte[len]; + in.readByteArray(payload); + sr.anqpElements[i] = + new AnqpInformationElement(vendorId, elementId, payload); + } + } return sr; } diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 4c224607829f..a9132a59ced5 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -58,6 +58,9 @@ public class WifiConfiguration implements Parcelable { /** {@hide} */ public static final int INVALID_NETWORK_ID = -1; + /** {@hide} */ + private String mPasspointManagementObjectTree; + /** * Recognized key management schemes. */ @@ -80,11 +83,16 @@ public class WifiConfiguration implements Parcelable { */ @SystemApi public static final int WPA2_PSK = 4; + /** + * Hotspot 2.0 r2 OSEN: + * @hide + */ + public static final int OSEN = 5; public static final String varName = "key_mgmt"; public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X", - "WPA2_PSK" }; + "WPA2_PSK", "OSEN" }; } /** @@ -97,10 +105,14 @@ public class WifiConfiguration implements Parcelable { public static final int WPA = 0; /** WPA2/IEEE 802.11i */ public static final int RSN = 1; + /** HS2.0 r2 OSEN + * @hide + */ + public static final int OSEN = 2; public static final String varName = "proto"; - public static final String[] strings = { "WPA", "RSN" }; + public static final String[] strings = { "WPA", "RSN", "OSEN" }; } /** @@ -159,10 +171,15 @@ public class WifiConfiguration implements Parcelable { public static final int TKIP = 2; /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */ public static final int CCMP = 3; + /** Hotspot 2.0 r2 OSEN + * @hide + */ + public static final int GTK_NOT_USED = 4; public static final String varName = "group"; - public static final String[] strings = { "WEP40", "WEP104", "TKIP", "CCMP" }; + public static final String[] strings = + { "WEP40", "WEP104", "TKIP", "CCMP", "GTK_NOT_USED" }; } /** Possible status of a network configuration. */ @@ -1735,6 +1752,16 @@ public class WifiConfiguration implements Parcelable { return shared || (UserHandle.getUserId(creatorUid) == userId); } + /** @hide */ + public void setPasspointManagementObjectTree(String passpointManagementObjectTree) { + mPasspointManagementObjectTree = passpointManagementObjectTree; + } + + /** @hide */ + public String getMoTree() { + return mPasspointManagementObjectTree; + } + /** copy constructor {@hide} */ public WifiConfiguration(WifiConfiguration source) { if (source != null) { @@ -1886,6 +1913,7 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(numNoInternetAccessReports); dest.writeInt(noInternetAccessExpected ? 1 : 0); dest.writeInt(shared ? 1 : 0); + dest.writeString(mPasspointManagementObjectTree); } /** Implement the Parcelable interface {@hide} */ @@ -1954,6 +1982,7 @@ public class WifiConfiguration implements Parcelable { config.numNoInternetAccessReports = in.readInt(); config.noInternetAccessExpected = in.readInt() != 0; config.shared = in.readInt() != 0; + config.mPasspointManagementObjectTree = in.readString(); return config; } diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index 605e8c0b0b1e..a0dbd85049b2 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -273,8 +273,11 @@ public class WifiEnterpriseConfig implements Parcelable { public static final int AKA = 5; /** EAP-Authentication and Key Agreement Prime */ public static final int AKA_PRIME = 6; + /** Hotspot 2.0 r2 OSEN */ + public static final int UNAUTH_TLS = 7; /** @hide */ - public static final String[] strings = { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'" }; + public static final String[] strings = + { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'", "WFA-UNAUTH-TLS" }; /** Prevent initialization */ private Eap() {} diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index db40cd8b3649..2ad3c2e16e21 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -26,28 +26,26 @@ import android.net.DhcpInfo; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; -import android.net.wifi.ScanSettings; import android.os.Binder; import android.os.Build; -import android.os.IBinder; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.Messenger; import android.os.RemoteException; import android.os.WorkSource; -import android.os.Messenger; import android.util.Log; import android.util.SparseArray; -import java.net.InetAddress; -import java.util.concurrent.CountDownLatch; - import com.android.internal.annotations.GuardedBy; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; +import java.net.InetAddress; import java.util.List; +import java.util.concurrent.CountDownLatch; /** * This class provides the primary API for managing all aspects of Wi-Fi @@ -114,6 +112,51 @@ public class WifiManager { public static final int WIFI_CREDENTIAL_FORGOT = 1; /** + * Broadcast intent action indicating that the a Passpoint release 2 icon has been received. + * @hide + */ + public static final String PASSPOINT_ICON_RECEIVED_ACTION = + "android.net.wifi.PASSPOINT_ICON_RECEIVED"; + /** @hide */ + public static final String EXTRA_PASSPOINT_ICON_BSSID = "bssid"; + /** @hide */ + public static final String EXTRA_PASSPOINT_ICON_FILE = "file"; + /** @hide */ + public static final String EXTRA_PASSPOINT_ICON_DATA = "icon"; + + /** + * Broadcast intent action indicating that the a Passpoint release + * 2 WNM frame has been received. + * @hide + */ + public static final String PASSPOINT_WNM_FRAME_RECEIVED_ACTION = + "android.net.wifi.PASSPOINT_WNM_FRAME_RECEIVED"; + /** + * Originating BSS + * @hide */ + public static final String EXTRA_PASSPOINT_WNM_BSSID = "bssid"; + /** + * SOAP-XML or OMA-DM + * @hide */ + public static final String EXTRA_PASSPOINT_WNM_METHOD = "method"; + /** + * Type of Passpoint match + * @hide */ + public static final String EXTRA_PASSPOINT_WNM_PPOINT_MATCH = "match"; + /** + * String + * @hide */ + public static final String EXTRA_PASSPOINT_WNM_URL = "url"; + /** + * Boolean true=ess, false=bss + * @hide */ + public static final String EXTRA_PASSPOINT_WNM_ESS = "ess"; + /** + * Delay in seconds + * @hide */ + public static final String EXTRA_PASSPOINT_WNM_DELAY = "delay"; + + /** * Broadcast intent action indicating that Wi-Fi has been enabled, disabled, * enabling, disabling, or unknown. One extra provides this state as an int. * Another extra provides the previous state, if available. @@ -779,6 +822,76 @@ public class WifiManager { } /** + * Add a Hotspot 2.0 release 2 Management Object + * @param mo The MO in XML form + * @return -1 for failure + * @hide + */ + public int addPasspointManagementObject(String mo) { + try { + return mService.addPasspointManagementObject(mo); + } catch (RemoteException e) { + return -1; + } + } + + /** + * Modify a Hotspot 2.0 release 2 Management Object + * @param fqdn The FQDN of the service provider + * @param mos A List of MO definitions to be updated + * @return the number of nodes updated, or -1 for failure + * @hide + */ + public int modifyPasspointManagementObject(String fqdn, + List<PasspointManagementObjectDefinition> mos) { + try { + return mService.modifyPasspointManagementObject(fqdn, mos); + } catch (RemoteException e) { + return -1; + } + } + + /** + * Query for a Hotspot 2.0 release 2 OSU icon + * @param bssid The BSSID of the AP + * @param fileName Icon file name + * @hide + */ + public void queryPasspointIcon(long bssid, String fileName) { + try { + mService.queryPasspointIcon(bssid, fileName); + } catch (RemoteException e) { + } + } + + /** + * Match the currently associated network against the SP matching the given FQDN + * @param fqdn FQDN of the SP + * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined] + * @hide + */ + public int matchProviderWithCurrentNetwork(String fqdn) { + try { + return mService.matchProviderWithCurrentNetwork(fqdn); + } catch (RemoteException e) { + return -1; + } + } + + /** + * Deauthenticate and set the re-authentication hold off time for the current network + * @param holdoff hold off time in milliseconds + * @param ess set if the hold off pertains to an ESS rather than a BSS + * @hide + */ + public void deauthenticateNetwork(long holdoff, boolean ess) { + try { + mService.deauthenticateNetwork(holdoff, ess); + } catch (RemoteException e) { + } + } + + /** * Remove the specified network from the list of configured networks. * This may result in the asynchronous delivery of state change * events. @@ -1199,30 +1312,6 @@ public class WifiManager { } /** - * An augmented version of getScanResults that returns ScanResults as well as OSU information - * wrapped in ScanInfo objects. - * @return - */ - public List<ScanInfo> getScanInfos() { - try { - return mService.getScanInfos(mContext.getOpPackageName()); - } catch (RemoteException e) { - return null; - } - } - - /** - * Notify the OSU framework about the currently selected OSU. - * @param osuID The OSU ID from ScanInfo.getOsuIdentity() - */ - public void setOsuSelection(int osuID) { - try { - mService.setOsuSelection(osuID); - } catch (RemoteException e) { - } - } - - /** * Check if scanning is always available. * * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results diff --git a/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl index 13efc361fbb3..fa666afd1c27 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl @@ -1,11 +1,11 @@ -/** - * Copyright (c) 2016, The Android Open Source Project +/* + * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -26,7 +26,7 @@ import android.net.wifi.nan.ConfigRequest; oneway interface IWifiNanEventListener { void onConfigCompleted(in ConfigRequest completedConfig); - void onConfigFailed(int reason); + void onConfigFailed(in ConfigRequest failedConfig, int reason); void onNanDown(int reason); void onIdentityChanged(); } diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl index ec9e4628d609..f382d97762d3 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl @@ -1,11 +1,11 @@ -/** - * Copyright (c) 2016, The Android Open Source Project +/* + * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl index 50c34d946918..d60d8caae70e 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl @@ -1,11 +1,11 @@ -/** - * Copyright (c) 2016, The Android Open Source Project +/* + * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java index eae0a55f7af1..5c18bd7e0f07 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java +++ b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java @@ -47,7 +47,8 @@ public class WifiNanEventListener { /** * Configuration failed callback event registration flag. Corresponding - * callback is {@link WifiNanEventListener#onConfigFailed(int)}. + * callback is + * {@link WifiNanEventListener#onConfigFailed(ConfigRequest, int)}. */ public static final int LISTEN_CONFIG_FAILED = 0x1 << 1; @@ -93,7 +94,7 @@ public class WifiNanEventListener { WifiNanEventListener.this.onConfigCompleted((ConfigRequest) msg.obj); break; case LISTEN_CONFIG_FAILED: - WifiNanEventListener.this.onConfigFailed(msg.arg1); + WifiNanEventListener.this.onConfigFailed((ConfigRequest) msg.obj, msg.arg1); break; case LISTEN_NAN_DOWN: WifiNanEventListener.this.onNanDown(msg.arg1); @@ -129,7 +130,7 @@ public class WifiNanEventListener { * * @param reason Failure reason code, see {@code NanSessionListener.FAIL_*}. */ - public void onConfigFailed(int reason) { + public void onConfigFailed(ConfigRequest failedConfig, int reason) { Log.w(TAG, "onConfigFailed: called in stub - override if interested or disable"); } @@ -173,11 +174,14 @@ public class WifiNanEventListener { } @Override - public void onConfigFailed(int reason) { - if (VDBG) Log.v(TAG, "onConfigFailed: reason=" + reason); + public void onConfigFailed(ConfigRequest failedConfig, int reason) { + if (VDBG) { + Log.v(TAG, "onConfigFailed: failedConfig=" + failedConfig + ", reason=" + reason); + } Message msg = mHandler.obtainMessage(LISTEN_CONFIG_FAILED); msg.arg1 = reason; + msg.obj = failedConfig; mHandler.sendMessage(msg); } diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java index d5e59f0edaf5..092508766570 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java @@ -303,8 +303,8 @@ public class WifiNanSessionListener { * message). Override to implement your custom response. * <p> * Note that either this callback or - * {@link WifiNanSessionListener#onMessageSendFail(int)} will be received - - * never both. + * {@link WifiNanSessionListener#onMessageSendFail(int, int)} will be + * received - never both. */ public void onMessageSendSuccess(int messageId) { if (VDBG) Log.v(TAG, "onMessageSendSuccess: called in stub - override if interested"); @@ -319,8 +319,8 @@ public class WifiNanSessionListener { * message). Override to implement your custom response. * <p> * Note that either this callback or - * {@link WifiNanSessionListener#onMessageSendSuccess()} will be received - - * never both + * {@link WifiNanSessionListener#onMessageSendSuccess(int)} will be received + * - never both * * @param reason The failure reason using {@code NanSessionListener.FAIL_*} * codes. |